<!DOCTYPE html>
<!-- saved from url=(0067)http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BASIC -->
<html lang="ru" class="ya-page_js_yes cc_cursor"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><script type="text/javascript" async="" src="./Advanced Bash-Scripting Guide_files/watch.js.Без названия"></script><script type="text/javascript" async="" src="./Advanced Bash-Scripting Guide_files/analytics.js.Без названия"></script>
<script src="./Advanced Bash-Scripting Guide_files/context.js.Без названия" type="text/javascript" async=""></script><script type="text/javascript" async="" charset="utf-8" src="./Advanced Bash-Scripting Guide_files/all.js.Без названия"></script><script type="text/javascript">TimeLoad1=(new Date()).getTime();TimeMax=1000;TimeAdd=50;sign_bad=0;</script>
<title>Advanced Bash-Scripting Guide</title>
<meta name="allsites-biz" content="a7a3d70c6d17a73140918996d03c014f">
<meta name="robots" content="index,follow">
<meta name="REVISIT-AFTER" content="1 days">
<meta name="Gogetlinks-verification" content="Proverka Gogetlinks 6382104256">
<meta name="yandex-verification" content="6608d43f19ca2aed">
<meta name="google-site-verification" content="eG78grVm7FzIrm4UqmE_0FQUqWuXHXNcsCTZKa3-ksM">
<meta name="loginza-verification" content="7100e4f6f88f6b8d17f45ab44cb88f4b">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href="./Advanced Bash-Scripting Guide_files/style2.css" type="text/css" rel="stylesheet">
<link rel="canonical" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html">
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async="" src="./Advanced Bash-Scripting Guide_files/js"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());

  gtag('config', 'UA-149378286-1');
</script>

<script data-ad-client="ca-pub-1593325451411063" async="" src="./Advanced Bash-Scripting Guide_files/f.txt"></script>

<script type="text/javascript" async="" src="./Advanced Bash-Scripting Guide_files/rotaban.js.Без названия"></script><style type="text/css">.ya-share2,
.ya-share2 * {
  line-height: normal;
}
.ya-share2 :link:hover,
.ya-share2 :visited:hover {
  color: #000 !important;
}
.ya-share2 input {
  color: inherit;
  font: inherit;
  margin: 0;
  line-height: normal;
}
.ya-share2__messenger-frame {
  display: none;
}
.ya-share2__container.ya-share2__container_color-scheme_blackwhite .ya-share2__badge,
.ya-share2__container.ya-share2__container_color-scheme_blackwhite .ya-share2__mobile-popup-badge {
  background-color: #000;
}
.ya-share2__container.ya-share2__container_color-scheme_whiteblack .ya-share2__badge,
.ya-share2__container.ya-share2__container_color-scheme_whiteblack .ya-share2__mobile-popup-badge {
  background-color: #fff;
}
.ya-share2__container.ya-share2__container_color-scheme_whiteblack .ya-share2__popup-body .ya-share2__mobile-popup-badge {
  background-color: #f2f2f2;
}
.ya-share2__container_shape_round .ya-share2__badge {
  border-radius: 50px;
}
.ya-share2__container_shape_round .ya-share2__icon {
  background-position: center;
}
.ya-share2__container_size_l {
  font-size: 20px;
}
.ya-share2__container_size_l .ya-share2__badge .ya-share2__icon {
  height: 48px;
  width: 48px;
  background-size: 48px 48px;
}
.ya-share2__container_shape_round.ya-share2__container_size_l .ya-share2__badge .ya-share2__icon:not(.ya-share2__icon_messenger-contact):not(.ya-share2__icon_more):not(.ya-share2__icon_copy) {
  background-size: 40px 40px;
}
.ya-share2__container_size_l .ya-share2__item_copy .ya-share2__icon_copy,
.ya-share2__container_size_l .ya-share2__item_more .ya-share2__icon_more {
  background-size: 32px 32px;
}
.ya-share2__container_size_l .ya-share2__title {
  line-height: 48px;
}
.ya-share2__container_size_l .ya-share2__badge + .ya-share2__title {
  margin-left: 16px;
}
.ya-share2__container_size_l .ya-share2__popup:not(.ya-share2__popup_mobile) {
  border-radius: 16px;
  box-shadow: 0px 16px 48px rgba(0,0,0,0.18), 0px 0px 8px rgba(0,0,0,0.1);
}
.ya-share2__container_size_l .ya-share2__popup:not(.ya-share2__popup_mobile) .ya-share2__item,
.ya-share2__container_size_l.ya-share2__container_as-popup .ya-share2__item {
  padding: 2px 16px;
}
.ya-share2__container_size_l .ya-share2__popup:not(.ya-share2__popup_mobile) > :first-child:not(:empty),
.ya-share2__container_size_l.ya-share2__container_as-popup > :first-child:not(:empty),
.ya-share2__container_size_l .ya-share2__popup:not(.ya-share2__popup_mobile) > :first-child:empty + :last-child:not(:empty):not(.ya-share2__copied-tooltip),
.ya-share2__container_size_l.ya-share2__container_as-popup > :first-child:empty + :last-child:not(:empty):not(.ya-share2__copied-tooltip) {
  padding-top: 8px;
}
.ya-share2__container_size_l .ya-share2__popup:not(.ya-share2__popup_mobile) > :last-child:not(:empty):not(.ya-share2__copied-tooltip),
.ya-share2__container_size_l.ya-share2__container_as-popup > :last-child:not(:empty):not(.ya-share2__copied-tooltip) {
  padding-bottom: 8px;
}
.ya-share2__container_size_l .ya-share2__popup_direction_bottom {
  top: 56px;
}
.ya-share2__container_size_l .ya-share2__popup_direction_top {
  bottom: 56px;
}
.ya-share2__container_size_l.ya-share2__container_alone .ya-share2__popup_direction_bottom,
.ya-share2__container_size_l .ya-share2__item_more.ya-share2__item_has-pretty-view .ya-share2__popup_direction_bottom {
  top: 72px;
}
.ya-share2__container_size_l.ya-share2__container_alone .ya-share2__popup_direction_top,
.ya-share2__container_size_l .ya-share2__item_more.ya-share2__item_has-pretty-view .ya-share2__popup_direction_top {
  bottom: 72px;
}
.ya-share2__container_size_l .ya-share2__item_more.ya-share2__item_has-pretty-view .ya-share2__link_more {
  padding: 8px 32px 8px 16px;
  font-size: 22px;
}
.ya-share2__container_size_l .ya-share2__item_more.ya-share2__item_has-pretty-view .ya-share2__link_more.ya-share2__link_more-button-type_short {
  padding: 8px;
  border: none;
  background: rgba(0,0,0,0.07);
}
.ya-share2__container_size_l .ya-share2__item_more.ya-share2__item_has-pretty-view .ya-share2__link_more .ya-share2__title {
  margin-left: 6px;
}
.ya-share2__container_size_l .ya-share2__messenger-contacts {
  margin-bottom: 12px;
}
.ya-share2__container_size_l .ya-share2__messenger-contacts::before {
  width: 16px;
  height: 16px;
  bottom: -7px;
  left: 32px;
}
.ya-share2__container_size_m {
  font-size: 13px;
}
.ya-share2__container_size_m .ya-share2__badge .ya-share2__icon {
  height: 24px;
  width: 24px;
  background-size: 24px 24px;
}
.ya-share2__container_shape_round.ya-share2__container_size_m .ya-share2__badge .ya-share2__icon:not(.ya-share2__icon_messenger-contact):not(.ya-share2__icon_more):not(.ya-share2__icon_copy) {
  background-size: 20px 20px;
}
.ya-share2__container_size_m .ya-share2__item_copy .ya-share2__icon_copy,
.ya-share2__container_size_m .ya-share2__item_more .ya-share2__icon_more {
  background-size: 16px 16px;
}
.ya-share2__container_size_m .ya-share2__title {
  line-height: 24px;
}
.ya-share2__container_size_m .ya-share2__badge + .ya-share2__title {
  margin-left: 10px;
}
.ya-share2__container_size_m .ya-share2__popup:not(.ya-share2__popup_mobile) {
  border-radius: 8px;
  box-shadow: 0px 8px 24px rgba(0,0,0,0.18), 0px 0px 4px rgba(0,0,0,0.1);
}
.ya-share2__container_size_m .ya-share2__popup:not(.ya-share2__popup_mobile) .ya-share2__item,
.ya-share2__container_size_m.ya-share2__container_as-popup .ya-share2__item {
  padding: 2px 8px;
}
.ya-share2__container_size_m .ya-share2__popup:not(.ya-share2__popup_mobile) > :first-child:not(:empty),
.ya-share2__container_size_m.ya-share2__container_as-popup > :first-child:not(:empty),
.ya-share2__container_size_m .ya-share2__popup:not(.ya-share2__popup_mobile) > :first-child:empty + :last-child:not(:empty):not(.ya-share2__copied-tooltip),
.ya-share2__container_size_m.ya-share2__container_as-popup > :first-child:empty + :last-child:not(:empty):not(.ya-share2__copied-tooltip) {
  padding-top: 8px;
}
.ya-share2__container_size_m .ya-share2__popup:not(.ya-share2__popup_mobile) > :last-child:not(:empty):not(.ya-share2__copied-tooltip),
.ya-share2__container_size_m.ya-share2__container_as-popup > :last-child:not(:empty):not(.ya-share2__copied-tooltip) {
  padding-bottom: 8px;
}
.ya-share2__container_size_m .ya-share2__popup_direction_bottom {
  top: 28px;
}
.ya-share2__container_size_m .ya-share2__popup_direction_top {
  bottom: 28px;
}
.ya-share2__container_size_m.ya-share2__container_alone .ya-share2__popup_direction_bottom,
.ya-share2__container_size_m .ya-share2__item_more.ya-share2__item_has-pretty-view .ya-share2__popup_direction_bottom {
  top: 36px;
}
.ya-share2__container_size_m.ya-share2__container_alone .ya-share2__popup_direction_top,
.ya-share2__container_size_m .ya-share2__item_more.ya-share2__item_has-pretty-view .ya-share2__popup_direction_top {
  bottom: 36px;
}
.ya-share2__container_size_m .ya-share2__item_more.ya-share2__item_has-pretty-view .ya-share2__link_more {
  padding: 4px 16px 4px 8px;
  font-size: 15px;
}
.ya-share2__container_size_m .ya-share2__item_more.ya-share2__item_has-pretty-view .ya-share2__link_more.ya-share2__link_more-button-type_short {
  padding: 4px;
  border: none;
  background: rgba(0,0,0,0.07);
}
.ya-share2__container_size_m .ya-share2__item_more.ya-share2__item_has-pretty-view .ya-share2__link_more .ya-share2__title {
  margin-left: 2px;
}
.ya-share2__container_size_m .ya-share2__messenger-contacts {
  margin-bottom: 6px;
}
.ya-share2__container_size_m .ya-share2__messenger-contacts::before {
  width: 10px;
  height: 10px;
  bottom: -4px;
  left: 15px;
}
.ya-share2__container_size_s {
  font-size: 12px;
}
.ya-share2__container_size_s .ya-share2__badge .ya-share2__icon {
  height: 18px;
  width: 18px;
  background-size: 18px 18px;
}
.ya-share2__container_shape_round.ya-share2__container_size_s .ya-share2__badge .ya-share2__icon:not(.ya-share2__icon_messenger-contact):not(.ya-share2__icon_more):not(.ya-share2__icon_copy) {
  background-size: 15px 15px;
}
.ya-share2__container_size_s .ya-share2__item_copy .ya-share2__icon_copy,
.ya-share2__container_size_s .ya-share2__item_more .ya-share2__icon_more {
  background-size: 12px 12px;
}
.ya-share2__container_size_s .ya-share2__title {
  line-height: 18px;
}
.ya-share2__container_size_s .ya-share2__badge + .ya-share2__title {
  margin-left: 6px;
}
.ya-share2__container_size_s .ya-share2__popup:not(.ya-share2__popup_mobile) {
  border-radius: 6px;
  box-shadow: 0px 6px 18px rgba(0,0,0,0.18), 0px 0px 3px rgba(0,0,0,0.1);
}
.ya-share2__container_size_s .ya-share2__popup:not(.ya-share2__popup_mobile) .ya-share2__item,
.ya-share2__container_size_s.ya-share2__container_as-popup .ya-share2__item {
  padding: 2px 6px;
}
.ya-share2__container_size_s .ya-share2__popup:not(.ya-share2__popup_mobile) > :first-child:not(:empty),
.ya-share2__container_size_s.ya-share2__container_as-popup > :first-child:not(:empty),
.ya-share2__container_size_s .ya-share2__popup:not(.ya-share2__popup_mobile) > :first-child:empty + :last-child:not(:empty):not(.ya-share2__copied-tooltip),
.ya-share2__container_size_s.ya-share2__container_as-popup > :first-child:empty + :last-child:not(:empty):not(.ya-share2__copied-tooltip) {
  padding-top: 6px;
}
.ya-share2__container_size_s .ya-share2__popup:not(.ya-share2__popup_mobile) > :last-child:not(:empty):not(.ya-share2__copied-tooltip),
.ya-share2__container_size_s.ya-share2__container_as-popup > :last-child:not(:empty):not(.ya-share2__copied-tooltip) {
  padding-bottom: 6px;
}
.ya-share2__container_size_s .ya-share2__popup_direction_bottom {
  top: 21px;
}
.ya-share2__container_size_s .ya-share2__popup_direction_top {
  bottom: 21px;
}
.ya-share2__container_size_s.ya-share2__container_alone .ya-share2__popup_direction_bottom,
.ya-share2__container_size_s .ya-share2__item_more.ya-share2__item_has-pretty-view .ya-share2__popup_direction_bottom {
  top: 27px;
}
.ya-share2__container_size_s.ya-share2__container_alone .ya-share2__popup_direction_top,
.ya-share2__container_size_s .ya-share2__item_more.ya-share2__item_has-pretty-view .ya-share2__popup_direction_top {
  bottom: 27px;
}
.ya-share2__container_size_s .ya-share2__item_more.ya-share2__item_has-pretty-view .ya-share2__link_more {
  padding: 3px 12px 3px 6px;
  font-size: 14px;
}
.ya-share2__container_size_s .ya-share2__item_more.ya-share2__item_has-pretty-view .ya-share2__link_more.ya-share2__link_more-button-type_short {
  padding: 3px;
  border: none;
  background: rgba(0,0,0,0.07);
}
.ya-share2__container_size_s .ya-share2__item_more.ya-share2__item_has-pretty-view .ya-share2__link_more .ya-share2__title {
  margin-left: 1px;
}
.ya-share2__container_size_s .ya-share2__messenger-contacts {
  margin-bottom: 4.5px;
}
.ya-share2__container_size_s .ya-share2__messenger-contacts::before {
  width: 8px;
  height: 8px;
  bottom: -3px;
  left: 11px;
}
.ya-share2__container_mobile .ya-share2__icon {
  background-position: center;
  background-repeat: no-repeat;
}
.ya-share2__container_mobile.ya-share2__container_size_l .ya-share2__icon {
  height: 56px;
  width: 56px;
}
.ya-share2__container_mobile.ya-share2__container_size_l .ya-share2__title {
  line-height: 56px;
}
.ya-share2__container_mobile.ya-share2__container_size_m .ya-share2__icon {
  height: 32px;
  width: 32px;
}
.ya-share2__container_mobile.ya-share2__container_size_m .ya-share2__title {
  line-height: 32px;
}
.ya-share2__container_mobile.ya-share2__container_size_s .ya-share2__icon {
  height: 24px;
  width: 24px;
}
.ya-share2__container_mobile.ya-share2__container_size_s .ya-share2__title {
  line-height: 24px;
}
.ya-share2__list.ya-share2__list_direction_horizontal {
  margin-top: -2px;
}
.ya-share2__list.ya-share2__list_direction_horizontal > .ya-share2__item {
  display: inline-block;
  vertical-align: top;
  padding: 0;
  margin: 2px 4px 0 0;
}
.ya-share2__list.ya-share2__list_direction_horizontal > .ya-share2__item:last-child {
  margin-right: 0;
}
.ya-share2__list.ya-share2__list_direction_horizontal > .ya-share2__item > .ya-share2__link > .ya-share2__title {
  display: none;
}
.ya-share2__list.ya-share2__list_direction_vertical > .ya-share2__item {
  display: block;
  margin: 4px 0;
}
.ya-share2__list.ya-share2__list_direction_vertical > .ya-share2__item:first-child {
  margin-top: 0;
}
.ya-share2__list.ya-share2__list_direction_vertical > .ya-share2__item:last-child {
  margin-bottom: 0;
}
.ya-share2__popup {
  position: absolute;
  display: none;
  z-index: 9999;
  background-color: #fff;
}
.ya-share2__popup_visible {
  display: block;
}
.ya-share2__popup_direction_auto {
  visibility: hidden;
}
.ya-share2__popup_direction_bottom,
.ya-share2__popup_direction_top {
  visibility: visible;
}
.ya-share2__popup_list-direction_horizontal {
  right: 0;
}
.ya-share2__popup_list-direction_vertical {
  left: 0;
}
.ya-share2__popup_x-direction_left {
  right: 0;
  left: auto;
}
.ya-share2__popup_x-direction_right {
  left: 0;
  right: auto;
}
.ya-share2__popup,
.ya-share2__container_as-popup {
  text-align: left;
}
.ya-share2__popup .ya-share2__list .ya-share2__item,
.ya-share2__popup .ya-share2__messenger-contacts-list_desktop .ya-share2__item,
.ya-share2__container_as-popup .ya-share2__list .ya-share2__item,
.ya-share2__container_as-popup .ya-share2__messenger-contacts-list_desktop .ya-share2__item {
  margin: 0;
}
.ya-share2__popup .ya-share2__list .ya-share2__item:hover,
.ya-share2__popup .ya-share2__messenger-contacts-list_desktop .ya-share2__item:hover,
.ya-share2__container_as-popup .ya-share2__list .ya-share2__item:hover,
.ya-share2__container_as-popup .ya-share2__messenger-contacts-list_desktop .ya-share2__item:hover,
.ya-share2__popup .ya-share2__list .ya-share2__item:focus,
.ya-share2__popup .ya-share2__messenger-contacts-list_desktop .ya-share2__item:focus,
.ya-share2__container_as-popup .ya-share2__list .ya-share2__item:focus,
.ya-share2__container_as-popup .ya-share2__messenger-contacts-list_desktop .ya-share2__item:focus {
  background: rgba(0,0,0,0.03);
}
.ya-share2__popup .ya-share2__list .ya-share2__item:active,
.ya-share2__popup .ya-share2__messenger-contacts-list_desktop .ya-share2__item:active,
.ya-share2__container_as-popup .ya-share2__list .ya-share2__item:active,
.ya-share2__container_as-popup .ya-share2__messenger-contacts-list_desktop .ya-share2__item:active {
  background: rgba(0,0,0,0.05);
}
.ya-share2__popup .ya-share2__list .ya-share2__item:hover,
.ya-share2__popup .ya-share2__messenger-contacts-list_desktop .ya-share2__item:hover,
.ya-share2__container_as-popup .ya-share2__list .ya-share2__item:hover,
.ya-share2__container_as-popup .ya-share2__messenger-contacts-list_desktop .ya-share2__item:hover,
.ya-share2__popup .ya-share2__list .ya-share2__item:focus,
.ya-share2__popup .ya-share2__messenger-contacts-list_desktop .ya-share2__item:focus,
.ya-share2__container_as-popup .ya-share2__list .ya-share2__item:focus,
.ya-share2__container_as-popup .ya-share2__messenger-contacts-list_desktop .ya-share2__item:focus,
.ya-share2__popup .ya-share2__list .ya-share2__item:active,
.ya-share2__popup .ya-share2__messenger-contacts-list_desktop .ya-share2__item:active,
.ya-share2__container_as-popup .ya-share2__list .ya-share2__item:active,
.ya-share2__container_as-popup .ya-share2__messenger-contacts-list_desktop .ya-share2__item:active {
  opacity: 1;
}
.ya-share2__container_color-scheme_whiteblack.ya-share2__popup .ya-share2__list .ya-share2__item:hover .ya-share2__badge,
.ya-share2__container_color-scheme_whiteblack.ya-share2__popup .ya-share2__messenger-contacts-list_desktop .ya-share2__item:hover .ya-share2__badge,
.ya-share2__container_color-scheme_whiteblack.ya-share2__container_as-popup .ya-share2__list .ya-share2__item:hover .ya-share2__badge,
.ya-share2__container_color-scheme_whiteblack.ya-share2__container_as-popup .ya-share2__messenger-contacts-list_desktop .ya-share2__item:hover .ya-share2__badge,
.ya-share2__container_color-scheme_whiteblack.ya-share2__popup .ya-share2__list .ya-share2__item:focus .ya-share2__badge,
.ya-share2__container_color-scheme_whiteblack.ya-share2__popup .ya-share2__messenger-contacts-list_desktop .ya-share2__item:focus .ya-share2__badge,
.ya-share2__container_color-scheme_whiteblack.ya-share2__container_as-popup .ya-share2__list .ya-share2__item:focus .ya-share2__badge,
.ya-share2__container_color-scheme_whiteblack.ya-share2__container_as-popup .ya-share2__messenger-contacts-list_desktop .ya-share2__item:focus .ya-share2__badge,
.ya-share2__container_color-scheme_whiteblack.ya-share2__popup .ya-share2__list .ya-share2__item:active .ya-share2__badge,
.ya-share2__container_color-scheme_whiteblack.ya-share2__popup .ya-share2__messenger-contacts-list_desktop .ya-share2__item:active .ya-share2__badge,
.ya-share2__container_color-scheme_whiteblack.ya-share2__container_as-popup .ya-share2__list .ya-share2__item:active .ya-share2__badge,
.ya-share2__container_color-scheme_whiteblack.ya-share2__container_as-popup .ya-share2__messenger-contacts-list_desktop .ya-share2__item:active .ya-share2__badge,
.ya-share2__container_color-scheme_normal.ya-share2__popup .ya-share2__list .ya-share2__item:hover.ya-share2__item_copy .ya-share2__badge,
.ya-share2__container_color-scheme_normal.ya-share2__popup .ya-share2__messenger-contacts-list_desktop .ya-share2__item:hover.ya-share2__item_copy .ya-share2__badge,
.ya-share2__container_color-scheme_normal.ya-share2__container_as-popup .ya-share2__list .ya-share2__item:hover.ya-share2__item_copy .ya-share2__badge,
.ya-share2__container_color-scheme_normal.ya-share2__container_as-popup .ya-share2__messenger-contacts-list_desktop .ya-share2__item:hover.ya-share2__item_copy .ya-share2__badge,
.ya-share2__container_color-scheme_normal.ya-share2__popup .ya-share2__list .ya-share2__item:focus.ya-share2__item_copy .ya-share2__badge,
.ya-share2__container_color-scheme_normal.ya-share2__popup .ya-share2__messenger-contacts-list_desktop .ya-share2__item:focus.ya-share2__item_copy .ya-share2__badge,
.ya-share2__container_color-scheme_normal.ya-share2__container_as-popup .ya-share2__list .ya-share2__item:focus.ya-share2__item_copy .ya-share2__badge,
.ya-share2__container_color-scheme_normal.ya-share2__container_as-popup .ya-share2__messenger-contacts-list_desktop .ya-share2__item:focus.ya-share2__item_copy .ya-share2__badge,
.ya-share2__container_color-scheme_normal.ya-share2__popup .ya-share2__list .ya-share2__item:active.ya-share2__item_copy .ya-share2__badge,
.ya-share2__container_color-scheme_normal.ya-share2__popup .ya-share2__messenger-contacts-list_desktop .ya-share2__item:active.ya-share2__item_copy .ya-share2__badge,
.ya-share2__container_color-scheme_normal.ya-share2__container_as-popup .ya-share2__list .ya-share2__item:active.ya-share2__item_copy .ya-share2__badge,
.ya-share2__container_color-scheme_normal.ya-share2__container_as-popup .ya-share2__messenger-contacts-list_desktop .ya-share2__item:active.ya-share2__item_copy .ya-share2__badge {
  background: transparent;
}
.ya-share2__container .ya-share2__messenger-contacts_desktop {
  background-color: #f5f5f5;
  position: relative;
}
.ya-share2__container .ya-share2__messenger-contacts_desktop:empty {
  display: none;
}
.ya-share2__container .ya-share2__messenger-contacts_desktop::before {
  content: '';
  transform: rotate(45deg);
  position: absolute;
  background-color: #f5f5f5;
}
.ya-share2__container .ya-share2__messenger-contacts_desktop .ya-share2__messenger-contacts-list {
  margin: 0;
  padding-left: 0;
}
.ya-share2__container .ya-share2__messenger-contacts_desktop .ya-share2__item {
  display: block;
}
.ya-share2__container .ya-share2__messenger-contacts_desktop .ya-share2__badge {
  background: none;
}
.ya-share2__container .ya-share2__messenger-contacts_desktop .ya-share2__icon {
  border-radius: 50px;
}
.ya-share2__container .ya-share2__messenger-contacts_desktop + .ya-share2__list {
  display: block;
}
.ya-share2__container.ya-share2__container_mobile .ya-share2__scroll-hider {
  height: 97px;
  overflow: hidden;
  padding-bottom: 16px;
}
.ya-share2__container.ya-share2__container_mobile .ya-share2__scroll-hider .ya-share2__messenger-contacts_mobile {
  overflow-x: scroll;
}
.ya-share2__container.ya-share2__container_mobile .ya-share2__scroll-hider .ya-share2__messenger-contacts_mobile:empty {
  display: none;
}
.ya-share2__container.ya-share2__container_mobile .ya-share2__scroll-hider .ya-share2__messenger-contacts_mobile .ya-share2__messenger-contacts-list {
  white-space: nowrap;
  height: 97px;
}
.ya-share2__container.ya-share2__container_mobile .ya-share2__scroll-hider + .ya-share2__header {
  border-top: 1px solid rgba(0,0,0,0.1);
}
.ya-share2__container.ya-share2__container_mobile .ya-share2__scroll-hider ~ .ya-share2__scroll-hider .ya-share2__popup-tile-wrapper {
  overflow-x: scroll;
}
.ya-share2__container.ya-share2__container_mobile .ya-share2__scroll-hider ~ .ya-share2__scroll-hider .ya-share2__popup-tile-wrapper .ya-share2__popup-tile {
  white-space: nowrap;
  height: 97px;
}
.ya-share2__container.ya-share2__container_mobile .ya-share2__scroll-hider .ya-share2__mobile-popup-badge {
  width: 56px;
  height: 56px;
  border-radius: 28px;
}
.ya-share2__container.ya-share2__container_mobile .ya-share2__scroll-hider .ya-share2__messenger-contacts-list .ya-share2__mobile-popup-badge {
  background: none;
}
.ya-share2__container.ya-share2__container_mobile .ya-share2__scroll-hider .ya-share2__item {
  width: 23%;
}
@media (min-width: 460px) {
  .ya-share2__container.ya-share2__container_mobile .ya-share2__scroll-hider .ya-share2__item {
    width: 18.6%;
  }
}
@media (min-width: 600px) {
  .ya-share2__container.ya-share2__container_mobile .ya-share2__scroll-hider .ya-share2__item {
    width: 15.6%;
  }
}
.ya-share2__popup.ya-share2__popup_mobile.ya-share2__popup_visible {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: rgba(0,0,0,0.8);
}
.ya-share2__popup.ya-share2__popup_mobile.ya-share2__popup_visible .ya-share2__popup-overlay {
  position: absolute;
  z-index: 1;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0,0,0,0.3);
  animation: overlayAppearance 0.2s cubic-bezier(0.42, 0, 1, 1) forwards;
}
.ya-share2__popup.ya-share2__popup_mobile.ya-share2__popup_visible .ya-share2__popup-content {
  display: flex;
  position: absolute;
  padding: 0;
  z-index: 2;
  bottom: 0;
  box-sizing: border-box;
  flex-direction: column;
  width: 100%;
  max-height: 70%;
  animation: popupAppearance 0.2s forwards;
}
.ya-share2__popup-content .ya-share2__popup-header {
  display: flex;
  align-items: center;
  min-height: 40px;
  padding: 14px 12px 14px 16px;
  border-bottom: 1px solid rgba(0,0,0,0.1);
  border-radius: 16px 16px 0 0;
  background-color: #fff;
}
.ya-share2__popup-content .ya-share2__popup-header .ya-share2__og-image,
.ya-share2__popup-content .ya-share2__popup-header .ya-share2__icon_og-image-stub,
.ya-share2__popup-content .ya-share2__popup-header .ya-share2__icon_closing-cross {
  flex-shrink: 0;
}
.ya-share2__popup-content .ya-share2__popup-header .ya-share2__popup-description {
  flex: 1;
  hyphens: auto;
  align-self: center;
  display: -webkit-box;
  max-height: 34px;
  margin: 0 8px 0 14px;
  overflow: hidden;
  font-size: 15px;
  line-height: 17px;
  text-overflow: ellipsis;
  word-break: break-word;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.ya-share2__popup-content .ya-share2__popup-body {
  overflow: auto;
  background-color: #fff;
}
.ya-share2__popup-content .ya-share2__popup-body .ya-share2__header {
  font-weight: 500;
  font-size: 18px;
  line-height: 20px;
  padding: 18px 16px 0;
  margin: 0;
}
.ya-share2__popup-content .ya-share2__messenger-contacts-list,
.ya-share2__popup-content .ya-share2__popup-tile {
  padding: 20px 12px 0;
  margin: 0;
}
.ya-share2__popup-content .ya-share2__messenger-contacts-list .ya-share2__item,
.ya-share2__popup-content .ya-share2__popup-tile .ya-share2__item {
  width: 25%;
  padding: 0;
  margin: 0 0 20px;
}
@media (min-width: 460px) {
  .ya-share2__popup-content .ya-share2__messenger-contacts-list .ya-share2__item,
  .ya-share2__popup-content .ya-share2__popup-tile .ya-share2__item {
    width: 20%;
  }
}
@media (min-width: 600px) {
  .ya-share2__popup-content .ya-share2__messenger-contacts-list .ya-share2__item,
  .ya-share2__popup-content .ya-share2__popup-tile .ya-share2__item {
    width: 16.66%;
  }
}
.ya-share2__popup-content .ya-share2__messenger-contacts-list .ya-share2__item .ya-share2__link,
.ya-share2__popup-content .ya-share2__popup-tile .ya-share2__item .ya-share2__link {
  width: 100%;
  height: 100%;
  color: rgba(0,0,0,0.8);
}
.ya-share2__popup-content .ya-share2__messenger-contacts-list .ya-share2__item .ya-share2__native-share-fake-link,
.ya-share2__popup-content .ya-share2__popup-tile .ya-share2__item .ya-share2__native-share-fake-link {
  display: inline-block;
  width: 100%;
  height: 100%;
}
.ya-share2__popup-content .ya-share2__messenger-contacts-list .ya-share2__mobile-popup-badge,
.ya-share2__popup-content .ya-share2__popup-tile .ya-share2__mobile-popup-badge {
  display: block;
  width: 52px;
  height: 52px;
  margin: 0 auto;
  border-radius: 26px;
}
.ya-share2__popup-content .ya-share2__messenger-contacts-list .ya-share2__mobile-popup-badge .ya-share2__icon,
.ya-share2__popup-content .ya-share2__popup-tile .ya-share2__mobile-popup-badge .ya-share2__icon {
  width: 100%;
  height: 100%;
  background-size: 32px;
  background-clip: content-box;
}
.ya-share2__popup-content .ya-share2__messenger-contacts-list .ya-share2__mobile-popup-badge .ya-share2__icon_messenger-contact,
.ya-share2__popup-content .ya-share2__popup-tile .ya-share2__mobile-popup-badge .ya-share2__icon_messenger-contact {
  background-size: 56px;
  border-radius: 50%;
}
.ya-share2__popup-content .ya-share2__messenger-contacts-list .ya-share2__mobile-popup-service-title,
.ya-share2__popup-content .ya-share2__popup-tile .ya-share2__mobile-popup-service-title {
  max-height: 15px;
  margin-top: 10px;
  padding: 0 4px;
  overflow: hidden;
  font-size: 13px;
  line-height: 15px;
  text-align: center;
  text-overflow: ellipsis;
}
.ya-share2__popup-content .ya-share2__icon {
  background-size: auto;
}
.ya-share2__popup-content .ya-share2__icon.ya-share2__og-image,
.ya-share2__popup-content .ya-share2__icon.ya-share2__icon_og-image-stub {
  box-sizing: border-box;
  width: 36px;
  height: 36px;
  border-radius: 6px;
}
.ya-share2__popup-content .ya-share2__icon.ya-share2__og-image {
  background-position: center;
  background-size: cover;
}
.ya-share2__popup-content .ya-share2__icon.ya-share2__icon_og-image-stub {
  padding: 6px;
  background-color: rgba(0,0,0,0.05);
  background-image: url("data:image/svg+xml,%3Csvg width='24' height='25' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M10.94 8.838a3 3 0 000 4.242 1 1 0 01-1.414 1.415 5 5 0 010-7.071l3.535-3.536a5 5 0 017.071 7.071l-1.092 1.093a1 1 0 01-1.415-1.415l1.093-1.092a3 3 0 10-4.243-4.243L10.94 8.838zm2.12 6.363a3 3 0 000-4.243 1 1 0 111.415-1.414 5 5 0 010 7.07l-3.5 3.501a5 5 0 01-7.071-7.071l1.025-1.025a1 1 0 011.414 1.414l-1.025 1.025a3 3 0 004.243 4.243l3.5-3.5z' fill='%23000' fill-opacity='.3'/%3E%3C/svg%3E");
}
.ya-share2__popup-content .ya-share2__icon.ya-share2__icon_closing-cross {
  box-sizing: border-box;
  cursor: pointer;
  width: 40px;
  height: 40px;
  padding: 10px;
  background-image: url("data:image/svg+xml,%3Csvg width='20' height='20' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M10 20c5.523 0 10-4.477 10-10S15.523 0 10 0 0 4.477 0 10s4.477 10 10 10zM5.403 5.403a1 1 0 011.414 0L10 8.586l3.183-3.183a1 1 0 111.414 1.414L11.414 10l3.183 3.183a1 1 0 01-1.414 1.414L10 11.414l-3.183 3.183a1 1 0 01-1.414-1.414L8.586 10 5.403 6.817a1 1 0 010-1.414z' fill='%23000' fill-opacity='.2'/%3E%3C/svg%3E");
}
.ya-share2__popup-content .ya-share2__icon.ya-share2__icon_closing-cross:hover {
  opacity: 0.8;
}
.ya-share2__popup-content .ya-share2__icon.ya-share2__icon_closing-cross:active {
  opacity: 0.6;
}
.ya-share2__popup-content .ya-share2__item.ya-share2__item_copy.ya-share2__item_copy-link-button .ya-share2__icon_copy-icon {
  width: 15px;
  height: 14px;
  opacity: 1;
  background-image: url("data:image/svg+xml,%3Csvg width='15' height='14' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M3.758 1a1 1 0 001 1h7.5a.5.5 0 01.5.5v7.497a1 1 0 002 0V2.5a2.5 2.5 0 00-2.5-2.5h-7.5a1 1 0 00-1 1zm-1.5 2h8a1.5 1.5 0 011.5 1.5v8a1.5 1.5 0 01-1.5 1.5h-8a1.5 1.5 0 01-1.5-1.5v-8a1.5 1.5 0 011.5-1.5zm.5 2v7h7V5h-7z' fill='%23000' fill-opacity='.3'/%3E%3C/svg%3E");
}
.ya-share2__popup-content .ya-share2__mobile-popup-badge.ya-share2__mobile-popup-badge_native-share {
  border: 1px solid rgba(0,0,0,0.15);
  background: #fff;
  box-sizing: border-box;
}
.ya-share2__popup-content .ya-share2__mobile-popup-badge.ya-share2__mobile-popup-badge_native-share .ya-share2__icon {
  background-image: url("data:image/svg+xml,%3Csvg width='22' height='22' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M4.583 12.604a1.604 1.604 0 100-3.208 1.604 1.604 0 000 3.208zm12.834 0a1.604 1.604 0 100-3.208 1.604 1.604 0 000 3.208zM12.604 11a1.604 1.604 0 11-3.208 0 1.604 1.604 0 013.208 0z' fill='%23000' fill-opacity='.3'/%3E%3C/svg%3E");
}
.ya-share2__popup-content .ya-share2__mobile-popup-copy-link .ya-share2__item.ya-share2__item_copy.ya-share2__item_copy-link-button {
  display: flex;
  align-items: center;
  margin: 8px auto 32px;
  padding: 12px 20px;
  border: 1px solid rgba(0,0,0,0.15);
  border-radius: 12px;
  background-color: #fff;
  font-size: 15px;
  line-height: 20px;
  color: #000;
}
.ya-share2__popup-content .ya-share2__mobile-popup-copy-link .ya-share2__item.ya-share2__item_copy.ya-share2__item_copy-link-button .ya-share2__link-title {
  padding-left: 8px;
}
.ya-share2__copied-tooltip {
  display: none;
  z-index: 9999;
  position: fixed;
  bottom: 6px;
  left: 50%;
  padding: 12px 20px;
  transform: translateX(-50%);
  border-radius: 22px;
  background: #fff;
  box-shadow: 0px 4px 12px rgba(0,0,0,0.15), 0px 0px 2px rgba(0,0,0,0.05);
  color: rgba(0,0,0,0.8);
  font-size: 15px;
  line-height: 20px;
  white-space: nowrap;
}
.ya-share2__copied-tooltip_shown {
  display: block;
  animation: tooltipAppearance 2s ease-out forwards;
}
@media (min-width: 721px) {
  .ya-share2__popup.ya-share2__popup_mobile.ya-share2__popup_visible {
    display: flex;
    justify-content: center;
    align-items: center;
  }
  .ya-share2__popup.ya-share2__popup_mobile.ya-share2__popup_visible .ya-share2__popup-content {
    width: 720px;
    min-height: 310px;
    padding: 20px 0;
    bottom: auto;
  }
  .ya-share2__popup.ya-share2__popup_mobile.ya-share2__popup_visible .ya-share2__popup-content .ya-share2__popup-body {
    border-radius: 0 0 16px 16px;
  }
}
@-moz-keyframes tooltipAppearance {
  0% {
    transform: translate(-50%, 0px);
    opacity: 0;
  }
  8% {
    transform: translate(-50%, -10px);
    opacity: 1;
  }
  92% {
    transform: translate(-50%, -10px);
    opacity: 1;
  }
  100% {
    transform: translate(-50%, 0px);
    opacity: 0;
  }
}
@-webkit-keyframes tooltipAppearance {
  0% {
    transform: translate(-50%, 0px);
    opacity: 0;
  }
  8% {
    transform: translate(-50%, -10px);
    opacity: 1;
  }
  92% {
    transform: translate(-50%, -10px);
    opacity: 1;
  }
  100% {
    transform: translate(-50%, 0px);
    opacity: 0;
  }
}
@-o-keyframes tooltipAppearance {
  0% {
    transform: translate(-50%, 0px);
    opacity: 0;
  }
  8% {
    transform: translate(-50%, -10px);
    opacity: 1;
  }
  92% {
    transform: translate(-50%, -10px);
    opacity: 1;
  }
  100% {
    transform: translate(-50%, 0px);
    opacity: 0;
  }
}
@keyframes tooltipAppearance {
  0% {
    transform: translate(-50%, 0px);
    opacity: 0;
  }
  8% {
    transform: translate(-50%, -10px);
    opacity: 1;
  }
  92% {
    transform: translate(-50%, -10px);
    opacity: 1;
  }
  100% {
    transform: translate(-50%, 0px);
    opacity: 0;
  }
}
@-moz-keyframes overlayAppearance {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
@-webkit-keyframes overlayAppearance {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
@-o-keyframes overlayAppearance {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
@keyframes overlayAppearance {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
@-moz-keyframes popupAppearance {
  from {
    transform: translateY(100%);
  }
  to {
    transform: translateY(0);
  }
}
@-webkit-keyframes popupAppearance {
  from {
    transform: translateY(100%);
  }
  to {
    transform: translateY(0);
  }
}
@-o-keyframes popupAppearance {
  from {
    transform: translateY(100%);
  }
  to {
    transform: translateY(0);
  }
}
@keyframes popupAppearance {
  from {
    transform: translateY(100%);
  }
  to {
    transform: translateY(0);
  }
}
.ya-share2__container,
.ya-share2__container .ya-share2__item {
  font-family: 'YS Text', Arial, sans-serif;
}
.ya-share2__list,
.ya-share2__badge,
.ya-share2__icon {
  display: inline-block;
  vertical-align: top;
}
.ya-share2__title {
  display: inline-block;
  vertical-align: bottom;
}
.ya-share2__list {
  padding: 0;
  margin: 0;
  list-style-type: none;
}
.ya-share2__link {
  display: block;
}
.ya-share2__item {
  display: inline-block;
  font-family: 'YS Text', Arial, sans-serif;
}
.ya-share2__item:not(.ya-share2__item_more):hover,
.ya-share2__item.ya-share2__item_more > .ya-share2__link:hover,
.ya-share2__item:not(.ya-share2__item_more):focus,
.ya-share2__item.ya-share2__item_more > .ya-share2__link:focus {
  cursor: pointer;
  opacity: 0.85;
}
.ya-share2__item:not(.ya-share2__item_more):active,
.ya-share2__item.ya-share2__item_more > .ya-share2__link:active {
  opacity: 0.7;
}
.ya-share2__link {
  text-decoration: none;
  white-space: nowrap;
}
.ya-share2__badge {
  border-radius: 4px;
  color: #fff;
  overflow: hidden;
  position: relative;
}
.ya-share2__container_mobile .ya-share2__badge {
  border-radius: 50%;
}
.ya-share2__title {
  color: #000;
}
.ya-share2__item_more {
  position: relative;
}
.ya-share2__item_more .ya-share2__link_more .ya-share2__title {
  display: none;
}
.ya-share2__item_more .ya-share2__icon_more {
  background-image: url("data:image/svg+xml,%3Csvg width='16' height='16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M1 8a1.5 1.5 0 113 0 1.5 1.5 0 01-3 0zm5.5 0a1.5 1.5 0 113 0 1.5 1.5 0 01-3 0zm7-1.5a1.5 1.5 0 100 3 1.5 1.5 0 000-3z' fill='%23999'/%3E%3C/svg%3E");
}
.ya-share2__container_color-scheme_blackwhite .ya-share2__item_more .ya-share2__icon_more {
  background-image: url("data:image/svg+xml,%3Csvg width='16' height='16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M1 8a1.5 1.5 0 113 0 1.5 1.5 0 01-3 0zm5.5 0a1.5 1.5 0 113 0 1.5 1.5 0 01-3 0zm7-1.5a1.5 1.5 0 100 3 1.5 1.5 0 000-3z' fill='%23fff'/%3E%3C/svg%3E");
}
.ya-share2__container_color-scheme_whiteblack .ya-share2__item_more .ya-share2__icon_more {
  background-image: url("data:image/svg+xml,%3Csvg width='16' height='16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M1 8a1.5 1.5 0 113 0 1.5 1.5 0 01-3 0zm5.5 0a1.5 1.5 0 113 0 1.5 1.5 0 01-3 0zm7-1.5a1.5 1.5 0 100 3 1.5 1.5 0 000-3z' fill='%23000'/%3E%3C/svg%3E");
}
.ya-share2__item_more.ya-share2__item_has-pretty-view .ya-share2__icon_more {
  background-image: url("data:image/svg+xml,%3Csvg width='16' height='16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M14.6 2.9a2.7 2.7 0 01-4.554 1.963L5.303 7.28a2.702 2.702 0 010 1.44l4.743 2.417a2.7 2.7 0 11-.834 1.708l-5.05-2.575a2.7 2.7 0 110-4.54l5.05-2.575A2.7 2.7 0 1114.6 2.9z' fill='%23000'/%3E%3C/svg%3E");
}
.ya-share2__item_more .ya-share2__badge,
.ya-share2__item_copy .ya-share2__badge {
  background: rgba(0,0,0,0.03);
}
.ya-share2__item_more .ya-share2__icon,
.ya-share2__item_copy .ya-share2__icon {
  background-position: center;
  background-repeat: no-repeat;
}
.ya-share2__item_more.ya-share2__item_has-pretty-view .ya-share2__link_more {
  background: rgba(0,0,0,0.03);
  border: 1px solid rgba(0,0,0,0.15);
  border-radius: 50px;
}
.ya-share2__item_more.ya-share2__item_has-pretty-view .ya-share2__link_more:not(.ya-share2__link_more-button-type_short):hover,
.ya-share2__item_more.ya-share2__item_has-pretty-view .ya-share2__link_more:not(.ya-share2__link_more-button-type_short):focus {
  border-color: rgba(0,0,0,0.25);
  opacity: 1;
}
.ya-share2__item_more.ya-share2__item_has-pretty-view .ya-share2__link_more:not(.ya-share2__link_more-button-type_short):active {
  border-color: rgba(0,0,0,0.4);
  opacity: 1;
}
.ya-share2__item_more.ya-share2__item_has-pretty-view .ya-share2__link_more:not(.ya-share2__link_more-button-type_short) .ya-share2__title {
  display: inline-block;
}
.ya-share2__item_more.ya-share2__item_has-pretty-view .ya-share2__badge_more {
  background: transparent;
}
.ya-share2__item_copy .ya-share2__icon {
  background-image: url("data:image/svg+xml,%3Csvg width='16' height='16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M4 2a1 1 0 001 1h7.5a.5.5 0 01.5.5v7.497a1 1 0 002 0V3.5A2.5 2.5 0 0012.5 1H5a1 1 0 00-1 1zM2.5 4h8A1.5 1.5 0 0112 5.5v8a1.5 1.5 0 01-1.5 1.5h-8A1.5 1.5 0 011 13.5v-8A1.5 1.5 0 012.5 4zM3 6v7h7V6H3z' fill='%23999'/%3E%3C/svg%3E");
}
.ya-share2__container_color-scheme_blackwhite .ya-share2__item_copy .ya-share2__icon {
  background-image: url("data:image/svg+xml,%3Csvg width='16' height='16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M4 2a1 1 0 001 1h7.5a.5.5 0 01.5.5v7.497a1 1 0 002 0V3.5A2.5 2.5 0 0012.5 1H5a1 1 0 00-1 1zM2.5 4h8A1.5 1.5 0 0112 5.5v8a1.5 1.5 0 01-1.5 1.5h-8A1.5 1.5 0 011 13.5v-8A1.5 1.5 0 012.5 4zM3 6v7h7V6H3z' fill='%23fff'/%3E%3C/svg%3E");
}
.ya-share2__container_color-scheme_whiteblack .ya-share2__item_copy .ya-share2__icon {
  background-image: url("data:image/svg+xml,%3Csvg width='16' height='16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M4 2a1 1 0 001 1h7.5a.5.5 0 01.5.5v7.497a1 1 0 002 0V3.5A2.5 2.5 0 0012.5 1H5a1 1 0 00-1 1zM2.5 4h8A1.5 1.5 0 0112 5.5v8a1.5 1.5 0 01-1.5 1.5h-8A1.5 1.5 0 011 13.5v-8A1.5 1.5 0 012.5 4zM3 6v7h7V6H3z' fill='%23000'/%3E%3C/svg%3E");
}
.ya-share2__item_copy .ya-share2__input_copy {
  display: none;
}
.ya-share2__item_copy .ya-share2__link_copy {
  display: inline-block;
}

.ya-share2__item_service_blogger .ya-share2__badge,
.ya-share2__item_service_blogger .ya-share2__mobile-popup-badge
{
    background-color: #fb8f3d;
}

.ya-share2__item_service_blogger .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M19.896 14.833A5.167 5.167 0 0114.729 20H9.166A5.167 5.167 0 014 14.833V9.167A5.166 5.166 0 019.166 4h2.608a5.167 5.167 0 015.167 5.167l.002.011c.037.536.484.96 1.03.96l.018-.002h.872c.57 0 1.034.463 1.034 1.034l-.001 3.663zM9.038 10.176h2.926a.993.993 0 000-1.987H9.038a.994.994 0 000 1.987zm5.867 3.83H9.032a.94.94 0 000 1.879h5.873a.94.94 0 100-1.88z' fill='%23FFF' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__container_color-scheme_whiteblack .ya-share2__item_service_blogger .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M19.896 14.833A5.167 5.167 0 0114.729 20H9.166A5.167 5.167 0 014 14.833V9.167A5.166 5.166 0 019.166 4h2.608a5.167 5.167 0 015.167 5.167l.002.011c.037.536.484.96 1.03.96l.018-.002h.872c.57 0 1.034.463 1.034 1.034l-.001 3.663zM9.038 10.176h2.926a.993.993 0 000-1.987H9.038a.994.994 0 000 1.987zm5.867 3.83H9.032a.94.94 0 000 1.879h5.873a.94.94 0 100-1.88z' fill='%23000' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__item_service_collections .ya-share2__badge,
.ya-share2__item_service_collections .ya-share2__mobile-popup-badge
{
    background-color: #f55;
}

.ya-share2__item_service_collections .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath d='M5.346 4c-.264 0-.477.104-.612.19a1.568 1.568 0 00-.367.336c-.19.237-.367.59-.367 1V15.2a.8.8 0 001.6 0V6.4a.8.8 0 01.8-.8h5.68a.8.8 0 100-1.6H5.346zm2.185 3.75a1.35 1.35 0 011.077-.55h9.002c.543 0 1.024.31 1.29.687.142.2.262.47.262.786 0 .329-.13.637-.367.878l-3.408 3.68a.737.737 0 000 .737l3.407 3.68c.215.216.367.494.4.815.033.326-.066.621-.222.851-.3.443-.83.684-1.362.684H8.743c-.393.012-.926-.032-1.272-.456a1.198 1.198 0 01-.251-.591c-.02-.138-.02-.278-.02-.359V8.747c0-.35.111-.71.33-.998z' fill='%23FFF' fill-rule='evenodd'/%3E %3C/svg%3E");
}

.ya-share2__container_color-scheme_whiteblack .ya-share2__item_service_collections .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath d='M5.346 4c-.264 0-.477.104-.612.19a1.568 1.568 0 00-.367.336c-.19.237-.367.59-.367 1V15.2a.8.8 0 001.6 0V6.4a.8.8 0 01.8-.8h5.68a.8.8 0 100-1.6H5.346zm2.185 3.75a1.35 1.35 0 011.077-.55h9.002c.543 0 1.024.31 1.29.687.142.2.262.47.262.786 0 .329-.13.637-.367.878l-3.408 3.68a.737.737 0 000 .737l3.407 3.68c.215.216.367.494.4.815.033.326-.066.621-.222.851-.3.443-.83.684-1.362.684H8.743c-.393.012-.926-.032-1.272-.456a1.198 1.198 0 01-.251-.591c-.02-.138-.02-.278-.02-.359V8.747c0-.35.111-.71.33-.998z' fill='%23000' fill-rule='evenodd'/%3E %3C/svg%3E");
}

.ya-share2__item_service_delicious .ya-share2__badge,
.ya-share2__item_service_delicious .ya-share2__mobile-popup-badge
{
    background-color: #31a9ff;
}

.ya-share2__item_service_delicious .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M4 12h8v8H4zm8-8h8v8h-7.984z' fill='%23FFF' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__container_color-scheme_whiteblack .ya-share2__item_service_delicious .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M4 12h8v8H4zm8-8h8v8h-7.984z' fill='%23000' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__item_service_digg .ya-share2__badge,
.ya-share2__item_service_digg .ya-share2__mobile-popup-badge
{
    background-color: #000;
}

.ya-share2__item_service_digg .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M5.555 10.814V14.1h.96s.18.005.18-.222v-3.287h-.96s-.18-.006-.18.222zm8.032 3.065v-3.287h-.96s-.18-.006-.18.222V14.1h.96s.18.006.18-.222zm-5.306 1.32c0 .227-.18.222-.18.222H4V9.497c0-.227.18-.222.18-.222h2.514V7.222c0-.227.18-.222.18-.222h1.408l-.001 8.199zm2.065 0c0 .227-.18.221-.18.221H8.761V9.496c0-.226.18-.221.18-.221h1.406v5.924zm0-7.103c0 .227-.18.222-.18.222H8.76V7.222c0-.227.18-.222.18-.222h1.408l-.001 1.096zm4.827 9.21c0 .228-.18.223-.18.223h-4.1v-1.096c0-.227.18-.222.18-.222h2.513v-.79h-2.694V9.497c0-.227.18-.222.18-.222l4.102.003v8.029zm4.826 0c0 .228-.18.223-.18.223h-4.1v-1.096c0-.227.18-.222.18-.222h2.514v-.79h-2.695V9.497c0-.227.18-.222.18-.222L20 9.279v8.028zm-1.585-3.427v-3.287h-.96s-.18-.006-.18.222V14.1h.96s.18.006.18-.222z' fill='%23FFF' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__container_color-scheme_whiteblack .ya-share2__item_service_digg .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M5.555 10.814V14.1h.96s.18.005.18-.222v-3.287h-.96s-.18-.006-.18.222zm8.032 3.065v-3.287h-.96s-.18-.006-.18.222V14.1h.96s.18.006.18-.222zm-5.306 1.32c0 .227-.18.222-.18.222H4V9.497c0-.227.18-.222.18-.222h2.514V7.222c0-.227.18-.222.18-.222h1.408l-.001 8.199zm2.065 0c0 .227-.18.221-.18.221H8.761V9.496c0-.226.18-.221.18-.221h1.406v5.924zm0-7.103c0 .227-.18.222-.18.222H8.76V7.222c0-.227.18-.222.18-.222h1.408l-.001 1.096zm4.827 9.21c0 .228-.18.223-.18.223h-4.1v-1.096c0-.227.18-.222.18-.222h2.513v-.79h-2.694V9.497c0-.227.18-.222.18-.222l4.102.003v8.029zm4.826 0c0 .228-.18.223-.18.223h-4.1v-1.096c0-.227.18-.222.18-.222h2.514v-.79h-2.695V9.497c0-.227.18-.222.18-.222L20 9.279v8.028zm-1.585-3.427v-3.287h-.96s-.18-.006-.18.222V14.1h.96s.18.006.18-.222z' fill='%23000' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__item_service_evernote .ya-share2__badge,
.ya-share2__item_service_evernote .ya-share2__mobile-popup-badge
{
    background-color: #24d666;
}

.ya-share2__item_service_evernote .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.277 7.109h1.517c.08 0 .16-.08.16-.16V5.313c0-.28.08-.559.159-.758l.04-.12L5.2 7.348l.16-.08c.239-.12.558-.16.917-.16zm11.654-.28c-.12-.638-.479-.917-.838-1.037-.36-.12-.718-.28-1.676-.4-.759-.08-1.557-.12-2.116-.12-.16-.438-.399-.917-1.317-1.156-.638-.16-1.796-.12-2.155-.08-.559.08-.758.319-.918.479-.16.16-.28.598-.28.878v1.556c0 .48-.318.838-.877.838H6.397c-.32 0-.559.04-.758.12-.16.12-.32.28-.4.4-.2.279-.239.598-.239.957 0 0 0 .28.08.798.04.4.479 3.033.878 3.911.16.36.28.48.599.639.718.32 2.354.639 3.152.758.759.08 1.278.32 1.557-.279 0 0 .04-.16.12-.36a6.3 6.3 0 00.28-1.915c0-.04.079-.04.079 0 0 .36-.08 1.557.838 1.876.36.12 1.118.24 1.876.32.678.079 1.197.358 1.197 2.114 0 1.078-.24 1.238-1.397 1.238-.958 0-1.317.04-1.317-.759 0-.598.599-.558 1.078-.558.2 0 .04-.16.04-.52 0-.398.24-.598 0-.598-1.557-.04-2.475 0-2.475 1.956 0 1.796.679 2.115 2.914 2.115 1.756 0 2.354-.04 3.073-2.275.16-.439.479-1.796.678-4.03.16-1.478-.12-5.788-.319-6.866zm-3.033 4.75c-.2 0-.32 0-.519.04h-.08s-.04 0-.04-.04v-.04c.08-.4.28-.878.878-.878.639.04.799.599.799 1.038v.04c0 .04-.04.04-.04.04-.04 0-.04 0-.04-.04-.28-.08-.599-.12-.958-.16z' fill='%23FFF' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__container_color-scheme_whiteblack .ya-share2__item_service_evernote .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.277 7.109h1.517c.08 0 .16-.08.16-.16V5.313c0-.28.08-.559.159-.758l.04-.12L5.2 7.348l.16-.08c.239-.12.558-.16.917-.16zm11.654-.28c-.12-.638-.479-.917-.838-1.037-.36-.12-.718-.28-1.676-.4-.759-.08-1.557-.12-2.116-.12-.16-.438-.399-.917-1.317-1.156-.638-.16-1.796-.12-2.155-.08-.559.08-.758.319-.918.479-.16.16-.28.598-.28.878v1.556c0 .48-.318.838-.877.838H6.397c-.32 0-.559.04-.758.12-.16.12-.32.28-.4.4-.2.279-.239.598-.239.957 0 0 0 .28.08.798.04.4.479 3.033.878 3.911.16.36.28.48.599.639.718.32 2.354.639 3.152.758.759.08 1.278.32 1.557-.279 0 0 .04-.16.12-.36a6.3 6.3 0 00.28-1.915c0-.04.079-.04.079 0 0 .36-.08 1.557.838 1.876.36.12 1.118.24 1.876.32.678.079 1.197.358 1.197 2.114 0 1.078-.24 1.238-1.397 1.238-.958 0-1.317.04-1.317-.759 0-.598.599-.558 1.078-.558.2 0 .04-.16.04-.52 0-.398.24-.598 0-.598-1.557-.04-2.475 0-2.475 1.956 0 1.796.679 2.115 2.914 2.115 1.756 0 2.354-.04 3.073-2.275.16-.439.479-1.796.678-4.03.16-1.478-.12-5.788-.319-6.866zm-3.033 4.75c-.2 0-.32 0-.519.04h-.08s-.04 0-.04-.04v-.04c.08-.4.28-.878.878-.878.639.04.799.599.799 1.038v.04c0 .04-.04.04-.04.04-.04 0-.04 0-.04-.04-.28-.08-.599-.12-.958-.16z' fill='%23000' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__item_service_facebook .ya-share2__badge,
.ya-share2__item_service_facebook .ya-share2__mobile-popup-badge
{
    background-color: #3b5998;
}

.ya-share2__item_service_facebook .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M13.423 20v-7.298h2.464l.369-2.845h-2.832V8.042c0-.824.23-1.385 1.417-1.385h1.515V4.111A20.255 20.255 0 0014.148 4c-2.183 0-3.678 1.326-3.678 3.76v2.097H8v2.845h2.47V20h2.953z' fill='%23FFF' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__container_color-scheme_whiteblack .ya-share2__item_service_facebook .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M13.423 20v-7.298h2.464l.369-2.845h-2.832V8.042c0-.824.23-1.385 1.417-1.385h1.515V4.111A20.255 20.255 0 0014.148 4c-2.183 0-3.678 1.326-3.678 3.76v2.097H8v2.845h2.47V20h2.953z' fill='%23000' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__item_service_linkedin .ya-share2__badge,
.ya-share2__item_service_linkedin .ya-share2__mobile-popup-badge
{
    background-color: #0083be;
}

.ya-share2__item_service_linkedin .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M4.246 8.954h3.41v10.281h-3.41zm1.725-4.935c-1.167 0-1.929.769-1.929 1.776 0 .987.74 1.777 1.884 1.777h.022c1.19 0 1.93-.79 1.93-1.777-.023-1.007-.74-1.776-1.907-1.776zm10.052 4.715c-1.81 0-2.62.997-3.073 1.698V8.976H9.54c.045.965 0 10.281 0 10.281h3.41v-5.742c0-.307.022-.614.112-.834.246-.613.807-1.25 1.75-1.25 1.233 0 1.727.944 1.727 2.325v5.501h3.41v-5.896c0-3.158-1.683-4.627-3.926-4.627z' fill='%23FFF' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__container_color-scheme_whiteblack .ya-share2__item_service_linkedin .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M4.246 8.954h3.41v10.281h-3.41zm1.725-4.935c-1.167 0-1.929.769-1.929 1.776 0 .987.74 1.777 1.884 1.777h.022c1.19 0 1.93-.79 1.93-1.777-.023-1.007-.74-1.776-1.907-1.776zm10.052 4.715c-1.81 0-2.62.997-3.073 1.698V8.976H9.54c.045.965 0 10.281 0 10.281h3.41v-5.742c0-.307.022-.614.112-.834.246-.613.807-1.25 1.75-1.25 1.233 0 1.727.944 1.727 2.325v5.501h3.41v-5.896c0-3.158-1.683-4.627-3.926-4.627z' fill='%23000' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__item_service_lj .ya-share2__badge,
.ya-share2__item_service_lj .ya-share2__mobile-popup-badge
{
    background-color: #0d425a;
}

.ya-share2__item_service_lj .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M17.815 13.3c.223 1.074.443 2.146.663 3.218.214 1.039.427 2.078.643 3.118.037.178-.148.385-.334.311-1.544-.565-3.063-1.135-4.585-1.706l-1.425-.534a.625.625 0 01-.318-.23l-7.39-8.903c-.067-.082-.082-.215-.06-.32.312-1.23.72-2.143 1.752-3.019C7.799 4.36 8.779 4.1 10.047 4.004c.156-.015.223.014.312.133l1.351 1.625v.001c1.968 2.367 3.935 4.733 5.897 7.099.109.124.18.275.208.438zM6.175 8.462c.69-1.795 2.3-3.004 3.835-3.301l-.185-.223a4.242 4.242 0 00-3.85 3.272l.2.252zm.504.601c.727-1.758 2.107-2.945 3.851-3.271l.89 1.06c-1.536.305-3.049 1.522-3.836 3.302l-.905-1.091zM9.364 8.9l3.926 4.719h-.002c.564.682-.014 2.656-.303 3.041l-4.89-5.89A6.12 6.12 0 019.364 8.9zm4.23 4.481L9.647 8.633c.69-.601 1.484-1.009 2.277-1.165l4.756 5.72c-.63.52-2.641.735-3.086.193zm3.36.298l.001-.001h-.001zm-2.93.526c1.03.208 2.32-.067 2.93-.526l.43 2.091.35 1.692c-.371.156-.69.386-.913.764l-1.528-.564-1.885-.712c.52-.853.69-1.922.616-2.745z' fill='%23FFF'/%3E%3C/svg%3E");
}

.ya-share2__container_color-scheme_whiteblack .ya-share2__item_service_lj .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M17.815 13.3c.223 1.074.443 2.146.663 3.218.214 1.039.427 2.078.643 3.118.037.178-.148.385-.334.311-1.544-.565-3.063-1.135-4.585-1.706l-1.425-.534a.625.625 0 01-.318-.23l-7.39-8.903c-.067-.082-.082-.215-.06-.32.312-1.23.72-2.143 1.752-3.019C7.799 4.36 8.779 4.1 10.047 4.004c.156-.015.223.014.312.133l1.351 1.625v.001c1.968 2.367 3.935 4.733 5.897 7.099.109.124.18.275.208.438zM6.175 8.462c.69-1.795 2.3-3.004 3.835-3.301l-.185-.223a4.242 4.242 0 00-3.85 3.272l.2.252zm.504.601c.727-1.758 2.107-2.945 3.851-3.271l.89 1.06c-1.536.305-3.049 1.522-3.836 3.302l-.905-1.091zM9.364 8.9l3.926 4.719h-.002c.564.682-.014 2.656-.303 3.041l-4.89-5.89A6.12 6.12 0 019.364 8.9zm4.23 4.481L9.647 8.633c.69-.601 1.484-1.009 2.277-1.165l4.756 5.72c-.63.52-2.641.735-3.086.193zm3.36.298l.001-.001h-.001zm-2.93.526c1.03.208 2.32-.067 2.93-.526l.43 2.091.35 1.692c-.371.156-.69.386-.913.764l-1.528-.564-1.885-.712c.52-.853.69-1.922.616-2.745z' fill='%23000'/%3E%3C/svg%3E");
}

.ya-share2__item_service_messenger .ya-share2__badge,
.ya-share2__item_service_messenger .ya-share2__mobile-popup-badge
{
    background-color: #03CECE;
}

.ya-share2__item_service_messenger .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M19.643 11.415L7.723 4.636a.703.703 0 00-1.048.62v1.826s3.961 1.542 4.284 1.662a.457.457 0 01.343.54c-.058.144-.18.128-.533.042-.352-.085-5.505-1.368-5.505-1.368a.62.62 0 00-.715.847l1.077 2.563s6.949.29 7.199.305c.247.015.393.134.397.327-.004.194-.15.312-.397.327-.25.014-7.199.305-7.199.305L4.55 15.196a.62.62 0 00.715.846s5.153-1.283 5.505-1.368c.353-.086.475-.102.533.042a.457.457 0 01-.343.54c-.323.12-4.284 1.663-4.284 1.663v1.825a.703.703 0 001.048.62l11.92-6.78a.658.658 0 000-1.169z' fill='%23FFF'/%3E%3C/svg%3E");
}

.ya-share2__container_color-scheme_whiteblack .ya-share2__item_service_messenger .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M19.643 11.415L7.723 4.636a.703.703 0 00-1.048.62v1.826s3.961 1.542 4.284 1.662a.457.457 0 01.343.54c-.058.144-.18.128-.533.042-.352-.085-5.505-1.368-5.505-1.368a.62.62 0 00-.715.847l1.077 2.563s6.949.29 7.199.305c.247.015.393.134.397.327-.004.194-.15.312-.397.327-.25.014-7.199.305-7.199.305L4.55 15.196a.62.62 0 00.715.846s5.153-1.283 5.505-1.368c.353-.086.475-.102.533.042a.457.457 0 01-.343.54c-.323.12-4.284 1.663-4.284 1.663v1.825a.703.703 0 001.048.62l11.92-6.78a.658.658 0 000-1.169z' fill='%23000'/%3E%3C/svg%3E");
}

.ya-share2__item_service_moimir .ya-share2__badge,
.ya-share2__item_service_moimir .ya-share2__mobile-popup-badge
{
    background-color: #168de2;
}

.ya-share2__item_service_moimir .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M8.889 9.667a1.333 1.333 0 100-2.667 1.333 1.333 0 000 2.667zm6.222 0a1.333 1.333 0 100-2.667 1.333 1.333 0 000 2.667zm4.77 6.108l-1.802-3.028a.879.879 0 00-1.188-.307.843.843 0 00-.313 1.166l.214.36a6.71 6.71 0 01-4.795 1.996 6.711 6.711 0 01-4.792-1.992l.217-.364a.844.844 0 00-.313-1.166.878.878 0 00-1.189.307l-1.8 3.028a.844.844 0 00.312 1.166.88.88 0 001.189-.307l.683-1.147a8.466 8.466 0 005.694 2.18 8.463 8.463 0 005.698-2.184l.685 1.151a.873.873 0 001.189.307.844.844 0 00.312-1.166z' fill='%23FFF' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__container_color-scheme_whiteblack .ya-share2__item_service_moimir .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M8.889 9.667a1.333 1.333 0 100-2.667 1.333 1.333 0 000 2.667zm6.222 0a1.333 1.333 0 100-2.667 1.333 1.333 0 000 2.667zm4.77 6.108l-1.802-3.028a.879.879 0 00-1.188-.307.843.843 0 00-.313 1.166l.214.36a6.71 6.71 0 01-4.795 1.996 6.711 6.711 0 01-4.792-1.992l.217-.364a.844.844 0 00-.313-1.166.878.878 0 00-1.189.307l-1.8 3.028a.844.844 0 00.312 1.166.88.88 0 001.189-.307l.683-1.147a8.466 8.466 0 005.694 2.18 8.463 8.463 0 005.698-2.184l.685 1.151a.873.873 0 001.189.307.844.844 0 00.312-1.166z' fill='%23000' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__item_service_odnoklassniki .ya-share2__badge,
.ya-share2__item_service_odnoklassniki .ya-share2__mobile-popup-badge
{
    background-color: #eb722e;
}

.ya-share2__item_service_odnoklassniki .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11.674 6.536a1.69 1.69 0 00-1.688 1.688c0 .93.757 1.687 1.688 1.687a1.69 1.69 0 001.688-1.687 1.69 1.69 0 00-1.688-1.688zm0 5.763a4.08 4.08 0 01-4.076-4.075 4.08 4.08 0 014.076-4.077 4.08 4.08 0 014.077 4.077 4.08 4.08 0 01-4.077 4.075zm-1.649 3.325a7.633 7.633 0 01-2.367-.98 1.194 1.194 0 011.272-2.022 5.175 5.175 0 005.489 0 1.194 1.194 0 111.272 2.022 7.647 7.647 0 01-2.367.98l2.279 2.28a1.194 1.194 0 01-1.69 1.688l-2.238-2.24-2.24 2.24a1.193 1.193 0 11-1.689-1.689l2.279-2.279' fill='%23FFF' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__container_color-scheme_whiteblack .ya-share2__item_service_odnoklassniki .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11.674 6.536a1.69 1.69 0 00-1.688 1.688c0 .93.757 1.687 1.688 1.687a1.69 1.69 0 001.688-1.687 1.69 1.69 0 00-1.688-1.688zm0 5.763a4.08 4.08 0 01-4.076-4.075 4.08 4.08 0 014.076-4.077 4.08 4.08 0 014.077 4.077 4.08 4.08 0 01-4.077 4.075zm-1.649 3.325a7.633 7.633 0 01-2.367-.98 1.194 1.194 0 011.272-2.022 5.175 5.175 0 005.489 0 1.194 1.194 0 111.272 2.022 7.647 7.647 0 01-2.367.98l2.279 2.28a1.194 1.194 0 01-1.69 1.688l-2.238-2.24-2.24 2.24a1.193 1.193 0 11-1.689-1.689l2.279-2.279' fill='%23000' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__item_service_pinterest .ya-share2__badge,
.ya-share2__item_service_pinterest .ya-share2__mobile-popup-badge
{
    background-color: #c20724;
}

.ya-share2__item_service_pinterest .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6 9.742c0 1.58.599 2.986 1.884 3.51.21.087.4.003.46-.23.043-.16.144-.568.189-.738.06-.23.037-.31-.133-.512-.37-.436-.608-1.001-.608-1.802 0-2.322 1.74-4.402 4.53-4.402 2.471 0 3.829 1.508 3.829 3.522 0 2.65-1.174 4.887-2.917 4.887-.963 0-1.683-.795-1.452-1.77.276-1.165.812-2.421.812-3.262 0-.752-.405-1.38-1.24-1.38-.985 0-1.775 1.017-1.775 2.38 0 .867.293 1.454.293 1.454L8.69 16.406c-.352 1.487-.053 3.309-.028 3.492.015.11.155.136.22.054.09-.119 1.262-1.564 1.66-3.008.113-.409.647-2.526.647-2.526.32.61 1.254 1.145 2.248 1.145 2.957 0 4.964-2.693 4.964-6.298C18.4 6.539 16.089 4 12.576 4 8.204 4 6 7.13 6 9.742z' fill='%23FFF' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__container_color-scheme_whiteblack .ya-share2__item_service_pinterest .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6 9.742c0 1.58.599 2.986 1.884 3.51.21.087.4.003.46-.23.043-.16.144-.568.189-.738.06-.23.037-.31-.133-.512-.37-.436-.608-1.001-.608-1.802 0-2.322 1.74-4.402 4.53-4.402 2.471 0 3.829 1.508 3.829 3.522 0 2.65-1.174 4.887-2.917 4.887-.963 0-1.683-.795-1.452-1.77.276-1.165.812-2.421.812-3.262 0-.752-.405-1.38-1.24-1.38-.985 0-1.775 1.017-1.775 2.38 0 .867.293 1.454.293 1.454L8.69 16.406c-.352 1.487-.053 3.309-.028 3.492.015.11.155.136.22.054.09-.119 1.262-1.564 1.66-3.008.113-.409.647-2.526.647-2.526.32.61 1.254 1.145 2.248 1.145 2.957 0 4.964-2.693 4.964-6.298C18.4 6.539 16.089 4 12.576 4 8.204 4 6 7.13 6 9.742z' fill='%23000' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__item_service_pocket .ya-share2__badge,
.ya-share2__item_service_pocket .ya-share2__mobile-popup-badge
{
    background-color: #ee4056;
}

.ya-share2__item_service_pocket .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M17.9 5c1.159 0 2.1.948 2.1 2.117v5.862c0 .108-.008.215-.024.32.016.156.024.314.024.473 0 3.36-3.582 6.085-8 6.085s-8-2.724-8-6.085c0-.159.008-.317.024-.473a2.148 2.148 0 01-.024-.32V7.117C4 5.948 4.94 5 6.1 5h11.8zM8.596 9.392L12 12.795l3.404-3.403a1.063 1.063 0 011.502 1.502l-4.132 4.131c-.21.21-.486.314-.76.311a1.062 1.062 0 01-.788-.31l-4.132-4.132a1.063 1.063 0 011.502-1.502z' fill='%23FFF' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__container_color-scheme_whiteblack .ya-share2__item_service_pocket .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M17.9 5c1.159 0 2.1.948 2.1 2.117v5.862c0 .108-.008.215-.024.32.016.156.024.314.024.473 0 3.36-3.582 6.085-8 6.085s-8-2.724-8-6.085c0-.159.008-.317.024-.473a2.148 2.148 0 01-.024-.32V7.117C4 5.948 4.94 5 6.1 5h11.8zM8.596 9.392L12 12.795l3.404-3.403a1.063 1.063 0 011.502 1.502l-4.132 4.131c-.21.21-.486.314-.76.311a1.062 1.062 0 01-.788-.31l-4.132-4.132a1.063 1.063 0 011.502-1.502z' fill='%23000' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__item_service_qzone .ya-share2__badge,
.ya-share2__item_service_qzone .ya-share2__mobile-popup-badge
{
    background-color: #f5b53c;
}

.ya-share2__item_service_qzone .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M17.367 14.463s-.105.148-.457.299l-.553.222.597 3.273c.062.282.25.983-.082 1.062-.17.04-.307-.067-.395-.121l-.769-.445-2.675-1.545c-.204-.122-.78-.546-1.093-.489-.205.038-.336.127-.483.216l-.77.445-2.39 1.386-.883.508c-.123.06-.301.058-.394-.025-.07-.063-.09-.253-.063-.388l.19-1.004.572-3.02c.047-.2.237-.975.166-1.137-.048-.107-.173-.196-.261-.267l-.61-.565-2.13-1.983c-.189-.153-.345-.345-.533-.496l-.235-.216c-.062-.078-.165-.235-.09-.369.142-.248.974-.218 1.335-.28l2.682-.31.82-.09c.146-.024.299-.004.413-.063.239-.123.51-.809.636-1.087l1.31-2.714c.151-.297.286-.603.431-.896.075-.15.133-.308.305-.356.162-.045.257.105.312.178.177.235.325.685.451.973l1.29 2.853c.104.238.363.964.54 1.074.266.166.858.108 1.227.172l2.841.292c.355.062 1.245.01 1.36.267.076.17-.072.314-.152.394l-.864.814-1.983 1.868c-.185.164-.77.637-.833.858-.04.14.02.414.088.722a95.62 95.62 0 01-1.182-.029c-.63-.007-2.616-.17-2.713-.178l-.84-.076c-.14-.023-.326.012-.4-.076v-.02c1.727-1.168 3.407-2.416 5.142-3.578l-.006-.044c-.146-.072-.359-.059-.54-.095-.385-.077-.79-.078-1.208-.147-.75-.124-1.59-.114-2.434-.114-1.172 0-2.329.03-3.35.21-.45.079-.894.095-1.309.197-.172.042-.358.03-.49.108l.007.012c.1.027.253.02.381.02l.928.019.808.025.813.032.591.032c.486.075 1.007.036 1.475.114.404.068.804.065 1.182.14.113.022.245.015.33.064v.006c-.039.094-.336.255-.432.318l-1.055.743-2.256 1.62-1.417.992c.003.048.024.035.045.061 1.15.167 2.52.258 3.77.262 1.298.005 2.465-.094 3.118-.193.561-.086 1.082-.147 1.653-.287.325-.08.521-.148.521-.148z' fill='%23FFF' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__container_color-scheme_whiteblack .ya-share2__item_service_qzone .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M17.367 14.463s-.105.148-.457.299l-.553.222.597 3.273c.062.282.25.983-.082 1.062-.17.04-.307-.067-.395-.121l-.769-.445-2.675-1.545c-.204-.122-.78-.546-1.093-.489-.205.038-.336.127-.483.216l-.77.445-2.39 1.386-.883.508c-.123.06-.301.058-.394-.025-.07-.063-.09-.253-.063-.388l.19-1.004.572-3.02c.047-.2.237-.975.166-1.137-.048-.107-.173-.196-.261-.267l-.61-.565-2.13-1.983c-.189-.153-.345-.345-.533-.496l-.235-.216c-.062-.078-.165-.235-.09-.369.142-.248.974-.218 1.335-.28l2.682-.31.82-.09c.146-.024.299-.004.413-.063.239-.123.51-.809.636-1.087l1.31-2.714c.151-.297.286-.603.431-.896.075-.15.133-.308.305-.356.162-.045.257.105.312.178.177.235.325.685.451.973l1.29 2.853c.104.238.363.964.54 1.074.266.166.858.108 1.227.172l2.841.292c.355.062 1.245.01 1.36.267.076.17-.072.314-.152.394l-.864.814-1.983 1.868c-.185.164-.77.637-.833.858-.04.14.02.414.088.722a95.62 95.62 0 01-1.182-.029c-.63-.007-2.616-.17-2.713-.178l-.84-.076c-.14-.023-.326.012-.4-.076v-.02c1.727-1.168 3.407-2.416 5.142-3.578l-.006-.044c-.146-.072-.359-.059-.54-.095-.385-.077-.79-.078-1.208-.147-.75-.124-1.59-.114-2.434-.114-1.172 0-2.329.03-3.35.21-.45.079-.894.095-1.309.197-.172.042-.358.03-.49.108l.007.012c.1.027.253.02.381.02l.928.019.808.025.813.032.591.032c.486.075 1.007.036 1.475.114.404.068.804.065 1.182.14.113.022.245.015.33.064v.006c-.039.094-.336.255-.432.318l-1.055.743-2.256 1.62-1.417.992c.003.048.024.035.045.061 1.15.167 2.52.258 3.77.262 1.298.005 2.465-.094 3.118-.193.561-.086 1.082-.147 1.653-.287.325-.08.521-.148.521-.148z' fill='%23000' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__item_service_reddit .ya-share2__badge,
.ya-share2__item_service_reddit .ya-share2__mobile-popup-badge
{
    background-color: #ff4500;
}

.ya-share2__item_service_reddit .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M16.542 10.63c-1.105-.636-2.494-1.033-4.025-1.118l.808-2.393 2.182.637c0 .963.78 1.742 1.743 1.742.964 0 1.758-.779 1.758-1.742C19.008 6.78 18.214 6 17.25 6c-.609 0-1.148.326-1.459.793l-2.65-.764a.482.482 0 00-.61.311l-1.063 3.172c-1.516.085-2.905.482-4.01 1.119a1.987 1.987 0 00-1.46-.623A1.995 1.995 0 004 12.004c0 .75.425 1.403 1.035 1.742-.029.17-.043.34-.043.51 0 2.62 3.146 4.744 7.015 4.744 3.855 0 7-2.124 7-4.744 0-.17-.013-.34-.042-.51A1.974 1.974 0 0020 12.004a1.995 1.995 0 00-1.998-1.996 2.01 2.01 0 00-1.46.623zM9.499 12.5a1.01 1.01 0 011.006 1.006.998.998 0 01-1.006.991.986.986 0 01-.992-.991.997.997 0 01.992-1.006zm5.002 0a.998.998 0 00-.992 1.006c0 .552.44.991.992.991a.998.998 0 001.006-.991 1.01 1.01 0 00-1.006-1.006zm-5.3 3.597a.484.484 0 01-.085-.694c.156-.226.482-.255.694-.085.567.44 1.474.68 2.197.68.709 0 1.616-.24 2.197-.68a.484.484 0 01.694.085.496.496 0 01-.085.694c-.737.58-1.885.907-2.806.907-.935 0-2.07-.326-2.806-.907zm8.05-7.59a.757.757 0 01-.752-.75c0-.426.34-.752.751-.752s.752.326.752.751c0 .41-.34.75-.752.75z' fill='%23FFF' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__container_color-scheme_whiteblack .ya-share2__item_service_reddit .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M16.542 10.63c-1.105-.636-2.494-1.033-4.025-1.118l.808-2.393 2.182.637c0 .963.78 1.742 1.743 1.742.964 0 1.758-.779 1.758-1.742C19.008 6.78 18.214 6 17.25 6c-.609 0-1.148.326-1.459.793l-2.65-.764a.482.482 0 00-.61.311l-1.063 3.172c-1.516.085-2.905.482-4.01 1.119a1.987 1.987 0 00-1.46-.623A1.995 1.995 0 004 12.004c0 .75.425 1.403 1.035 1.742-.029.17-.043.34-.043.51 0 2.62 3.146 4.744 7.015 4.744 3.855 0 7-2.124 7-4.744 0-.17-.013-.34-.042-.51A1.974 1.974 0 0020 12.004a1.995 1.995 0 00-1.998-1.996 2.01 2.01 0 00-1.46.623zM9.499 12.5a1.01 1.01 0 011.006 1.006.998.998 0 01-1.006.991.986.986 0 01-.992-.991.997.997 0 01.992-1.006zm5.002 0a.998.998 0 00-.992 1.006c0 .552.44.991.992.991a.998.998 0 001.006-.991 1.01 1.01 0 00-1.006-1.006zm-5.3 3.597a.484.484 0 01-.085-.694c.156-.226.482-.255.694-.085.567.44 1.474.68 2.197.68.709 0 1.616-.24 2.197-.68a.484.484 0 01.694.085.496.496 0 01-.085.694c-.737.58-1.885.907-2.806.907-.935 0-2.07-.326-2.806-.907zm8.05-7.59a.757.757 0 01-.752-.75c0-.426.34-.752.751-.752s.752.326.752.751c0 .41-.34.75-.752.75z' fill='%23000' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__item_service_renren .ya-share2__badge,
.ya-share2__item_service_renren .ya-share2__mobile-popup-badge
{
    background-color: #1760a7;
}

.ya-share2__item_service_renren .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12.019 15.562l-.001-.003-.018.002a.055.055 0 00.019.001zM7.71 12.398l.146-.68c.048-.205.03-.452.03-.692V9.812L7.88 8c-.139 0-.278.043-.393.076-.358.102-.666.201-.962.352-1.158.59-2.022 1.565-2.387 2.944-.343 1.297-.007 2.652.522 3.507.118.19.269.48.44.61.135-.02.272-.15.375-.217a6.06 6.06 0 00.622-.452l.24-.229c.63-.506 1.075-1.346 1.373-2.193zm4.276 3.164h.02a.382.382 0 00-.019-.003v.003zm-3.01-.888l-.258-.575-.088-.264h-.01l-.264.498c-.176.288-.358.574-.557.839a6.5 6.5 0 01-.85.944l-.517.422.012.024.287.14c.206.091.43.173.657.235.788.217 1.811.177 2.545-.053.178-.055.643-.194.739-.305v-.017c-.177-.092-.324-.254-.47-.381a5.573 5.573 0 01-1.225-1.507zm10.884-3.302c-.365-1.379-1.23-2.354-2.387-2.944a5.277 5.277 0 00-.962-.352c-.115-.033-.254-.077-.393-.076l-.005 1.812v1.214c0 .24-.019.487.029.692l.147.68c.297.847.741 1.687 1.372 2.193l.24.23c.196.164.402.309.622.45.103.067.24.198.375.218.171-.13.322-.42.44-.61.529-.855.865-2.21.522-3.507zm-3.66 3.8c-.2-.265-.381-.55-.557-.839l-.264-.498h-.011l-.088.264-.258.575a5.576 5.576 0 01-1.226 1.507c-.145.127-.292.29-.469.38v.018c.096.111.561.25.739.305.734.23 1.757.27 2.545.053a4.85 4.85 0 00.657-.234l.287-.141a1.31 1.31 0 00.012-.024l-.516-.422a6.5 6.5 0 01-.85-.944zm-1.653-2.727c.068-.192.097-.402.146-.61.05-.21.024-.484.024-.727V9.753l-.006-1.741c-.015-.008-.02-.01-.047-.012-.197.047-.326.05-.592.14-.357.102-.685.275-.985.44-.289.16-.53.388-.78.587-.097.077-.199.19-.308.312l.01.01a1.19 1.19 0 00-.01.012l.36.47c.232.359.445.763.581 1.213.326 1.079.182 2.411-.235 3.273a4.9 4.9 0 01-.445.75l-.258.323a.018.018 0 01-.003.007c.004.007.01.016.012.022h.008c.395-.215.686-.574 1.027-.844.189-.15.354-.35.504-.54.404-.514.755-1.046.997-1.73zm-2.55 3.085l-.259-.323a4.903 4.903 0 01-.445-.75c-.417-.862-.561-2.194-.235-3.273.136-.45.35-.854.58-1.214L12 9.501l-.01-.011.01-.01a2.791 2.791 0 00-.308-.313c-.25-.2-.491-.427-.78-.586-.3-.166-.628-.339-.985-.44-.266-.09-.395-.094-.592-.141a.083.083 0 00-.047.012l-.006 1.741v1.355c0 .243-.026.517.024.727.049.208.078.418.146.61.242.684.593 1.216.997 1.73.15.19.315.39.505.54.34.27.63.629 1.026.844h.008c.001-.006.008-.015.012-.022a.019.019 0 01-.003-.007z' fill='%23FFF' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__container_color-scheme_whiteblack .ya-share2__item_service_renren .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12.019 15.562l-.001-.003-.018.002a.055.055 0 00.019.001zM7.71 12.398l.146-.68c.048-.205.03-.452.03-.692V9.812L7.88 8c-.139 0-.278.043-.393.076-.358.102-.666.201-.962.352-1.158.59-2.022 1.565-2.387 2.944-.343 1.297-.007 2.652.522 3.507.118.19.269.48.44.61.135-.02.272-.15.375-.217a6.06 6.06 0 00.622-.452l.24-.229c.63-.506 1.075-1.346 1.373-2.193zm4.276 3.164h.02a.382.382 0 00-.019-.003v.003zm-3.01-.888l-.258-.575-.088-.264h-.01l-.264.498c-.176.288-.358.574-.557.839a6.5 6.5 0 01-.85.944l-.517.422.012.024.287.14c.206.091.43.173.657.235.788.217 1.811.177 2.545-.053.178-.055.643-.194.739-.305v-.017c-.177-.092-.324-.254-.47-.381a5.573 5.573 0 01-1.225-1.507zm10.884-3.302c-.365-1.379-1.23-2.354-2.387-2.944a5.277 5.277 0 00-.962-.352c-.115-.033-.254-.077-.393-.076l-.005 1.812v1.214c0 .24-.019.487.029.692l.147.68c.297.847.741 1.687 1.372 2.193l.24.23c.196.164.402.309.622.45.103.067.24.198.375.218.171-.13.322-.42.44-.61.529-.855.865-2.21.522-3.507zm-3.66 3.8c-.2-.265-.381-.55-.557-.839l-.264-.498h-.011l-.088.264-.258.575a5.576 5.576 0 01-1.226 1.507c-.145.127-.292.29-.469.38v.018c.096.111.561.25.739.305.734.23 1.757.27 2.545.053a4.85 4.85 0 00.657-.234l.287-.141a1.31 1.31 0 00.012-.024l-.516-.422a6.5 6.5 0 01-.85-.944zm-1.653-2.727c.068-.192.097-.402.146-.61.05-.21.024-.484.024-.727V9.753l-.006-1.741c-.015-.008-.02-.01-.047-.012-.197.047-.326.05-.592.14-.357.102-.685.275-.985.44-.289.16-.53.388-.78.587-.097.077-.199.19-.308.312l.01.01a1.19 1.19 0 00-.01.012l.36.47c.232.359.445.763.581 1.213.326 1.079.182 2.411-.235 3.273a4.9 4.9 0 01-.445.75l-.258.323a.018.018 0 01-.003.007c.004.007.01.016.012.022h.008c.395-.215.686-.574 1.027-.844.189-.15.354-.35.504-.54.404-.514.755-1.046.997-1.73zm-2.55 3.085l-.259-.323a4.903 4.903 0 01-.445-.75c-.417-.862-.561-2.194-.235-3.273.136-.45.35-.854.58-1.214L12 9.501l-.01-.011.01-.01a2.791 2.791 0 00-.308-.313c-.25-.2-.491-.427-.78-.586-.3-.166-.628-.339-.985-.44-.266-.09-.395-.094-.592-.141a.083.083 0 00-.047.012l-.006 1.741v1.355c0 .243-.026.517.024.727.049.208.078.418.146.61.242.684.593 1.216.997 1.73.15.19.315.39.505.54.34.27.63.629 1.026.844h.008c.001-.006.008-.015.012-.022a.019.019 0 01-.003-.007z' fill='%23000' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__item_service_sinaWeibo .ya-share2__badge,
.ya-share2__item_service_sinaWeibo .ya-share2__mobile-popup-badge
{
    background-color: #c53220;
}

.ya-share2__item_service_sinaWeibo .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M10.266 14.696c-.103.421.55.447.64.063.037-.191-.103-.332-.282-.332-.167 0-.333.128-.358.269zm-.128.945c.102-.498-.307-.869-.793-.843-.46.038-.843.358-.92.754-.115.511.307.882.793.844.46-.026.843-.345.92-.755zm3.797-3.157c-1.586-.997-3.707-1.01-5.42-.447-.857.28-1.764.818-2.301 1.495-.627.793-.882 1.815-.23 2.8.958 1.431 3.413 2.033 5.675 1.508 1.33-.307 2.749-1.048 3.35-2.326.562-1.177-.052-2.378-1.074-3.03zm-3.17.498c.945.167 1.7.755 1.827 1.739.243 1.854-2.173 3.336-4.026 2.327a1.933 1.933 0 01-.742-2.723c.435-.767 1.266-1.266 2.148-1.355a2.75 2.75 0 01.793.012zm6.11-.37c-.268-.18-.538-.281-.856-.383-.308-.103-.359-.154-.243-.46.076-.218.14-.41.166-.666.14-1.15-.793-1.495-1.854-1.406-.498.039-.92.167-1.355.307-.281.09-.806.384-.92.205-.064-.09.013-.23.038-.32.166-.626.23-1.496-.384-1.88-.447-.28-1.227-.204-1.7-.038-2.556.87-6.455 4.552-5.663 7.479.18.664.55 1.163.908 1.521 1.061 1.061 2.71 1.65 4.231 1.866 1.112.154 2.263.14 3.375-.064 1.815-.332 3.554-1.15 4.679-2.607.754-.972.997-2.352 0-3.235a3.334 3.334 0 00-.422-.319zm1.623-3.682c.652 1.483-.064 2.148.166 2.66.192.421.767.46 1.023.14.191-.243.294-.959.307-1.278a4.193 4.193 0 00-1.125-3.12c-.984-1.073-2.276-1.444-3.694-1.303-.256.025-.46.064-.601.217-.332.358-.166.882.294.959.384.063 1.342-.23 2.416.396.498.307.971.792 1.214 1.33zm-3.45-.562c-.282.345-.078.87.408.856.294-.012.358-.05.677.051.307.103.626.448.64.857.025.268-.282.895.32 1.061a.523.523 0 00.536-.166c.115-.128.166-.371.192-.575.089-.857-.333-1.598-1.01-2.02-.384-.23-1.445-.46-1.764-.064z' fill='%23FFF' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__container_color-scheme_whiteblack .ya-share2__item_service_sinaWeibo .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M10.266 14.696c-.103.421.55.447.64.063.037-.191-.103-.332-.282-.332-.167 0-.333.128-.358.269zm-.128.945c.102-.498-.307-.869-.793-.843-.46.038-.843.358-.92.754-.115.511.307.882.793.844.46-.026.843-.345.92-.755zm3.797-3.157c-1.586-.997-3.707-1.01-5.42-.447-.857.28-1.764.818-2.301 1.495-.627.793-.882 1.815-.23 2.8.958 1.431 3.413 2.033 5.675 1.508 1.33-.307 2.749-1.048 3.35-2.326.562-1.177-.052-2.378-1.074-3.03zm-3.17.498c.945.167 1.7.755 1.827 1.739.243 1.854-2.173 3.336-4.026 2.327a1.933 1.933 0 01-.742-2.723c.435-.767 1.266-1.266 2.148-1.355a2.75 2.75 0 01.793.012zm6.11-.37c-.268-.18-.538-.281-.856-.383-.308-.103-.359-.154-.243-.46.076-.218.14-.41.166-.666.14-1.15-.793-1.495-1.854-1.406-.498.039-.92.167-1.355.307-.281.09-.806.384-.92.205-.064-.09.013-.23.038-.32.166-.626.23-1.496-.384-1.88-.447-.28-1.227-.204-1.7-.038-2.556.87-6.455 4.552-5.663 7.479.18.664.55 1.163.908 1.521 1.061 1.061 2.71 1.65 4.231 1.866 1.112.154 2.263.14 3.375-.064 1.815-.332 3.554-1.15 4.679-2.607.754-.972.997-2.352 0-3.235a3.334 3.334 0 00-.422-.319zm1.623-3.682c.652 1.483-.064 2.148.166 2.66.192.421.767.46 1.023.14.191-.243.294-.959.307-1.278a4.193 4.193 0 00-1.125-3.12c-.984-1.073-2.276-1.444-3.694-1.303-.256.025-.46.064-.601.217-.332.358-.166.882.294.959.384.063 1.342-.23 2.416.396.498.307.971.792 1.214 1.33zm-3.45-.562c-.282.345-.078.87.408.856.294-.012.358-.05.677.051.307.103.626.448.64.857.025.268-.282.895.32 1.061a.523.523 0 00.536-.166c.115-.128.166-.371.192-.575.089-.857-.333-1.598-1.01-2.02-.384-.23-1.445-.46-1.764-.064z' fill='%23000' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__item_service_skype .ya-share2__badge,
.ya-share2__item_service_skype .ya-share2__mobile-popup-badge
{
    background-color: #00aff0;
}

.ya-share2__item_service_skype .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M19.537 13.698c.115-.52.176-1.06.176-1.614 0-4.155-3.415-7.524-7.63-7.524-.444 0-.88.038-1.304.11A4.444 4.444 0 008.425 4C5.981 4 4 5.954 4 8.364c0 .805.222 1.56.608 2.207a7.428 7.428 0 00-.155 1.513c0 4.156 3.416 7.4 7.63 7.4.477 0 .944-.044 1.397-.126.623.33 1.335.642 2.092.642 2.444 0 4.425-1.953 4.425-4.364a4.3 4.3 0 00-.46-1.938zm-3.974 1.457c-.294.418-.725.747-1.293.984-.567.238-1.239.356-2.016.356-.933 0-1.702-.162-2.308-.486a2.986 2.986 0 01-1.047-.934c-.268-.39-.403-.768-.403-1.137 0-.213.08-.395.242-.547a.855.855 0 01.615-.229.76.76 0 01.512.178c.14.119.26.294.358.527.12.278.25.51.39.695.139.185.336.34.589.46.254.12.587.18 1 .18.566 0 1.027-.12 1.382-.364.354-.243.532-.547.532-.91a.919.919 0 00-.287-.702 1.88 1.88 0 00-.741-.412 13.21 13.21 0 00-1.216-.303c-.678-.146-1.247-.318-1.703-.513-.458-.196-.822-.463-1.09-.8-.269-.34-.403-.759-.403-1.26 0-.48.142-.904.426-1.275.283-.372.693-.658 1.23-.858.537-.2 1.17-.299 1.895-.299.58 0 1.082.066 1.505.198.423.133.774.309 1.053.528.28.22.484.45.612.691.13.24.194.477.194.705 0 .21-.08.4-.241.567a.8.8 0 01-.603.252c-.22 0-.386-.05-.5-.151-.114-.101-.237-.266-.37-.495a2.27 2.27 0 00-.618-.768c-.241-.184-.627-.276-1.16-.276-.494 0-.893.1-1.196.3-.303.199-.455.44-.455.72 0 .173.053.324.155.45.103.128.245.235.426.326.18.091.363.162.547.214.185.052.49.126.916.225a15.47 15.47 0 011.446.38c.432.138.8.307 1.103.503.302.198.54.45.709.752.17.302.255.673.255 1.111 0 .525-.148.998-.442 1.417z' fill='%23FFF' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__container_color-scheme_whiteblack .ya-share2__item_service_skype .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M19.537 13.698c.115-.52.176-1.06.176-1.614 0-4.155-3.415-7.524-7.63-7.524-.444 0-.88.038-1.304.11A4.444 4.444 0 008.425 4C5.981 4 4 5.954 4 8.364c0 .805.222 1.56.608 2.207a7.428 7.428 0 00-.155 1.513c0 4.156 3.416 7.4 7.63 7.4.477 0 .944-.044 1.397-.126.623.33 1.335.642 2.092.642 2.444 0 4.425-1.953 4.425-4.364a4.3 4.3 0 00-.46-1.938zm-3.974 1.457c-.294.418-.725.747-1.293.984-.567.238-1.239.356-2.016.356-.933 0-1.702-.162-2.308-.486a2.986 2.986 0 01-1.047-.934c-.268-.39-.403-.768-.403-1.137 0-.213.08-.395.242-.547a.855.855 0 01.615-.229.76.76 0 01.512.178c.14.119.26.294.358.527.12.278.25.51.39.695.139.185.336.34.589.46.254.12.587.18 1 .18.566 0 1.027-.12 1.382-.364.354-.243.532-.547.532-.91a.919.919 0 00-.287-.702 1.88 1.88 0 00-.741-.412 13.21 13.21 0 00-1.216-.303c-.678-.146-1.247-.318-1.703-.513-.458-.196-.822-.463-1.09-.8-.269-.34-.403-.759-.403-1.26 0-.48.142-.904.426-1.275.283-.372.693-.658 1.23-.858.537-.2 1.17-.299 1.895-.299.58 0 1.082.066 1.505.198.423.133.774.309 1.053.528.28.22.484.45.612.691.13.24.194.477.194.705 0 .21-.08.4-.241.567a.8.8 0 01-.603.252c-.22 0-.386-.05-.5-.151-.114-.101-.237-.266-.37-.495a2.27 2.27 0 00-.618-.768c-.241-.184-.627-.276-1.16-.276-.494 0-.893.1-1.196.3-.303.199-.455.44-.455.72 0 .173.053.324.155.45.103.128.245.235.426.326.18.091.363.162.547.214.185.052.49.126.916.225a15.47 15.47 0 011.446.38c.432.138.8.307 1.103.503.302.198.54.45.709.752.17.302.255.673.255 1.111 0 .525-.148.998-.442 1.417z' fill='%23000' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__item_service_surfingbird .ya-share2__badge,
.ya-share2__item_service_surfingbird .ya-share2__mobile-popup-badge
{
    background-color: #30baff;
}

.ya-share2__item_service_surfingbird .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M17.315 8.49l-.214 1.987-3.436 3.382h-1.826l-.698 1.826v2.523l-2.47-.698 2.846-5.1L4 8.167l5.638.752L6.899 5l7.463 4.027 2.202-2.47h1.02L20 7.631z' fill='%23FFF' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__container_color-scheme_whiteblack .ya-share2__item_service_surfingbird .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M17.315 8.49l-.214 1.987-3.436 3.382h-1.826l-.698 1.826v2.523l-2.47-.698 2.846-5.1L4 8.167l5.638.752L6.899 5l7.463 4.027 2.202-2.47h1.02L20 7.631z' fill='%23000' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__item_service_telegram .ya-share2__badge,
.ya-share2__item_service_telegram .ya-share2__mobile-popup-badge
{
    background-color: #64a9dc;
}

.ya-share2__item_service_telegram .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M18.92 6.089L4.747 11.555c-.967.388-.962.928-.176 1.168l3.534 1.104 1.353 4.146c.164.454.083.634.56.634.368 0 .53-.168.736-.368.13-.127.903-.88 1.767-1.719l3.677 2.717c.676.373 1.165.18 1.333-.628l2.414-11.374c.247-.99-.378-1.44-1.025-1.146zM8.66 13.573l7.967-5.026c.398-.242.763-.112.463.154l-6.822 6.155-.265 2.833-1.343-4.116z' fill='%23FFF' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__container_color-scheme_whiteblack .ya-share2__item_service_telegram .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M18.92 6.089L4.747 11.555c-.967.388-.962.928-.176 1.168l3.534 1.104 1.353 4.146c.164.454.083.634.56.634.368 0 .53-.168.736-.368.13-.127.903-.88 1.767-1.719l3.677 2.717c.676.373 1.165.18 1.333-.628l2.414-11.374c.247-.99-.378-1.44-1.025-1.146zM8.66 13.573l7.967-5.026c.398-.242.763-.112.463.154l-6.822 6.155-.265 2.833-1.343-4.116z' fill='%23000' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__item_service_tencentWeibo .ya-share2__badge,
.ya-share2__item_service_tencentWeibo .ya-share2__mobile-popup-badge
{
    background-color: #53a9d7;
}

.ya-share2__item_service_tencentWeibo .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M8.813 6.01a4.397 4.397 0 00-4.326 6.121c.087.199.312.29.511.2a.382.382 0 00.206-.51 3.566 3.566 0 01-.286-1.668A3.616 3.616 0 018.76 6.79a3.615 3.615 0 013.366 3.84 3.615 3.615 0 01-4.65 3.218.39.39 0 00-.486.263.394.394 0 00.262.485c.315.093.647.152.977.174a4.397 4.397 0 004.677-4.087A4.398 4.398 0 008.813 6.01zm-1.348 5.658a1.67 1.67 0 10-.46-.655c-.274.27-.565.59-.854.966-1.022 1.315-2.224 3.694-2.148 7.007.006.204.157.484.355.497l.04.002c.213.015.394-.301.391-.516-.064-2.458.6-4.662 1.955-6.423.242-.316.488-.626.72-.878zm12.388 4.106c-1.307-.48-2.302-1.27-2.95-2.352a4.873 4.873 0 01-.354-.71.819.819 0 00.337-.36.829.829 0 00-.395-1.098.822.822 0 00-1.098.392.822.822 0 00.724 1.177c.091.237.218.516.39.81.483.812 1.431 1.912 3.196 2.558a.226.226 0 00.278-.113c0-.006.005-.01.007-.022a.224.224 0 00-.135-.282zm-3.767-1.676a2.04 2.04 0 01-1.707-3.042 2.039 2.039 0 012.784-.787 2.04 2.04 0 01.786 2.783 1.92 1.92 0 01-.268.378.223.223 0 00.014.314c.09.082.234.074.313-.016a2.489 2.489 0 10-4.017-2.89 2.493 2.493 0 002.08 3.708.224.224 0 00.015-.448z' fill='%23FFF' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__container_color-scheme_whiteblack .ya-share2__item_service_tencentWeibo .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M8.813 6.01a4.397 4.397 0 00-4.326 6.121c.087.199.312.29.511.2a.382.382 0 00.206-.51 3.566 3.566 0 01-.286-1.668A3.616 3.616 0 018.76 6.79a3.615 3.615 0 013.366 3.84 3.615 3.615 0 01-4.65 3.218.39.39 0 00-.486.263.394.394 0 00.262.485c.315.093.647.152.977.174a4.397 4.397 0 004.677-4.087A4.398 4.398 0 008.813 6.01zm-1.348 5.658a1.67 1.67 0 10-.46-.655c-.274.27-.565.59-.854.966-1.022 1.315-2.224 3.694-2.148 7.007.006.204.157.484.355.497l.04.002c.213.015.394-.301.391-.516-.064-2.458.6-4.662 1.955-6.423.242-.316.488-.626.72-.878zm12.388 4.106c-1.307-.48-2.302-1.27-2.95-2.352a4.873 4.873 0 01-.354-.71.819.819 0 00.337-.36.829.829 0 00-.395-1.098.822.822 0 00-1.098.392.822.822 0 00.724 1.177c.091.237.218.516.39.81.483.812 1.431 1.912 3.196 2.558a.226.226 0 00.278-.113c0-.006.005-.01.007-.022a.224.224 0 00-.135-.282zm-3.767-1.676a2.04 2.04 0 01-1.707-3.042 2.039 2.039 0 012.784-.787 2.04 2.04 0 01.786 2.783 1.92 1.92 0 01-.268.378.223.223 0 00.014.314c.09.082.234.074.313-.016a2.489 2.489 0 10-4.017-2.89 2.493 2.493 0 002.08 3.708.224.224 0 00.015-.448z' fill='%23000' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__item_service_tumblr .ya-share2__badge,
.ya-share2__item_service_tumblr .ya-share2__mobile-popup-badge
{
    background-color: #547093;
}

.ya-share2__item_service_tumblr .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12.72 7.7h3.699v2.857h-3.7v4.102c0 .928-.01 1.463.087 1.726.098.262.343.534.61.69.355.213.758.32 1.214.32.81 0 1.616-.264 2.417-.79v2.522c-.683.322-1.302.55-1.857.678a7.94 7.94 0 01-1.798.195 4.905 4.905 0 01-1.724-.276 4.215 4.215 0 01-1.438-.79c-.399-.343-.673-.706-.826-1.09-.154-.386-.23-.945-.23-1.676v-5.611H7V8.29c.628-.203 1.357-.496 1.804-.877.45-.382.809-.84 1.08-1.374.272-.534.459-1.214.56-2.039h2.276v3.7z' fill='%23FFF' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__container_color-scheme_whiteblack .ya-share2__item_service_tumblr .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12.72 7.7h3.699v2.857h-3.7v4.102c0 .928-.01 1.463.087 1.726.098.262.343.534.61.69.355.213.758.32 1.214.32.81 0 1.616-.264 2.417-.79v2.522c-.683.322-1.302.55-1.857.678a7.94 7.94 0 01-1.798.195 4.905 4.905 0 01-1.724-.276 4.215 4.215 0 01-1.438-.79c-.399-.343-.673-.706-.826-1.09-.154-.386-.23-.945-.23-1.676v-5.611H7V8.29c.628-.203 1.357-.496 1.804-.877.45-.382.809-.84 1.08-1.374.272-.534.459-1.214.56-2.039h2.276v3.7z' fill='%23000' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__item_service_twitter .ya-share2__badge,
.ya-share2__item_service_twitter .ya-share2__mobile-popup-badge
{
    background-color: #00aced;
}

.ya-share2__item_service_twitter .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M20 7.539a6.56 6.56 0 01-1.885.517 3.294 3.294 0 001.443-1.816 6.575 6.575 0 01-2.085.796 3.283 3.283 0 00-5.593 2.994A9.32 9.32 0 015.114 6.6a3.28 3.28 0 001.016 4.382 3.274 3.274 0 01-1.487-.41v.041a3.285 3.285 0 002.633 3.218 3.305 3.305 0 01-1.482.056 3.286 3.286 0 003.066 2.28A6.585 6.585 0 014 17.524 9.291 9.291 0 009.032 19c6.038 0 9.34-5 9.34-9.337 0-.143-.004-.285-.01-.425A6.672 6.672 0 0020 7.538z' fill='%23FFF' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__container_color-scheme_whiteblack .ya-share2__item_service_twitter .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M20 7.539a6.56 6.56 0 01-1.885.517 3.294 3.294 0 001.443-1.816 6.575 6.575 0 01-2.085.796 3.283 3.283 0 00-5.593 2.994A9.32 9.32 0 015.114 6.6a3.28 3.28 0 001.016 4.382 3.274 3.274 0 01-1.487-.41v.041a3.285 3.285 0 002.633 3.218 3.305 3.305 0 01-1.482.056 3.286 3.286 0 003.066 2.28A6.585 6.585 0 014 17.524 9.291 9.291 0 009.032 19c6.038 0 9.34-5 9.34-9.337 0-.143-.004-.285-.01-.425A6.672 6.672 0 0020 7.538z' fill='%23000' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__item_service_viber .ya-share2__badge,
.ya-share2__item_service_viber .ya-share2__mobile-popup-badge
{
    background-color: #7b519d;
}

.ya-share2__item_service_viber .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23FFF' fill-rule='evenodd'%3E%3Cpath d='M18.434 15.574c-.484-.391-1.002-.743-1.511-1.102-1.016-.718-1.945-.773-2.703.38-.426.648-1.021.677-1.644.392-1.718-.782-3.044-1.989-3.821-3.743-.344-.777-.34-1.473.465-2.022.425-.29.854-.634.82-1.268-.045-.828-2.043-3.593-2.832-3.885a1.429 1.429 0 00-.984 0C4.373 4.95 3.606 6.48 4.34 8.292c2.19 5.405 6.043 9.167 11.349 11.463.302.13.638.183.808.23 1.208.012 2.623-1.158 3.032-2.318.393-1.117-.438-1.56-1.096-2.093zM12.485 4.88c3.879.6 5.668 2.454 6.162 6.38.045.363-.09.909.426.919.538.01.408-.528.413-.89.045-3.699-3.163-7.127-6.888-7.253-.281.04-.863-.195-.9.438-.024.427.466.357.787.406z'/%3E%3Cpath d='M13.244 5.957c-.373-.045-.865-.222-.953.299-.09.546.458.49.811.57 2.395.538 3.23 1.414 3.624 3.802.057.349-.057.89.532.8.436-.066.278-.53.315-.802.02-2.293-1.936-4.38-4.329-4.669z'/%3E%3Cpath d='M13.464 7.832c-.249.006-.493.033-.585.3-.137.4.152.496.446.544.983.158 1.5.74 1.598 1.725.027.268.195.484.452.454.356-.043.389-.361.378-.664.017-1.106-1.227-2.385-2.289-2.359z'/%3E%3C/g%3E%3C/svg%3E");
}

.ya-share2__container_color-scheme_whiteblack .ya-share2__item_service_viber .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23000' fill-rule='evenodd'%3E%3Cpath d='M18.434 15.574c-.484-.391-1.002-.743-1.511-1.102-1.016-.718-1.945-.773-2.703.38-.426.648-1.021.677-1.644.392-1.718-.782-3.044-1.989-3.821-3.743-.344-.777-.34-1.473.465-2.022.425-.29.854-.634.82-1.268-.045-.828-2.043-3.593-2.832-3.885a1.429 1.429 0 00-.984 0C4.373 4.95 3.606 6.48 4.34 8.292c2.19 5.405 6.043 9.167 11.349 11.463.302.13.638.183.808.23 1.208.012 2.623-1.158 3.032-2.318.393-1.117-.438-1.56-1.096-2.093zM12.485 4.88c3.879.6 5.668 2.454 6.162 6.38.045.363-.09.909.426.919.538.01.408-.528.413-.89.045-3.699-3.163-7.127-6.888-7.253-.281.04-.863-.195-.9.438-.024.427.466.357.787.406z'/%3E%3Cpath d='M13.244 5.957c-.373-.045-.865-.222-.953.299-.09.546.458.49.811.57 2.395.538 3.23 1.414 3.624 3.802.057.349-.057.89.532.8.436-.066.278-.53.315-.802.02-2.293-1.936-4.38-4.329-4.669z'/%3E%3Cpath d='M13.464 7.832c-.249.006-.493.033-.585.3-.137.4.152.496.446.544.983.158 1.5.74 1.598 1.725.027.268.195.484.452.454.356-.043.389-.361.378-.664.017-1.106-1.227-2.385-2.289-2.359z'/%3E%3C/g%3E%3C/svg%3E");
}

.ya-share2__item_service_vkontakte .ya-share2__badge,
.ya-share2__item_service_vkontakte .ya-share2__mobile-popup-badge
{
    background-color: #4680c2;
}

.ya-share2__item_service_vkontakte .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M19.623 7.66c.12-.372 0-.643-.525-.643h-1.745c-.44 0-.644.237-.763.491 0 0-.898 2.17-2.152 3.576-.406.406-.593.542-.813.542-.119 0-.271-.136-.271-.508V7.644c0-.44-.136-.644-.509-.644H10.1c-.27 0-.44.203-.44.407 0 .423.627.525.694 1.711v2.576c0 .559-.101.66-.322.66-.593 0-2.033-2.185-2.897-4.676-.17-.492-.339-.678-.78-.678H4.593C4.085 7 4 7.237 4 7.491c0 .458.593 2.762 2.762 5.813 1.44 2.084 3.49 3.202 5.338 3.202 1.118 0 1.254-.254 1.254-.678v-1.575c0-.509.101-.594.457-.594.254 0 .712.136 1.746 1.136 1.186 1.186 1.39 1.728 2.05 1.728h1.745c.509 0 .746-.254.61-.745-.152-.492-.728-1.203-1.474-2.05-.407-.475-1.017-1-1.203-1.255-.254-.339-.186-.474 0-.78-.017 0 2.118-3.015 2.338-4.032' fill='%23FFF' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__container_color-scheme_whiteblack .ya-share2__item_service_vkontakte .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M19.623 7.66c.12-.372 0-.643-.525-.643h-1.745c-.44 0-.644.237-.763.491 0 0-.898 2.17-2.152 3.576-.406.406-.593.542-.813.542-.119 0-.271-.136-.271-.508V7.644c0-.44-.136-.644-.509-.644H10.1c-.27 0-.44.203-.44.407 0 .423.627.525.694 1.711v2.576c0 .559-.101.66-.322.66-.593 0-2.033-2.185-2.897-4.676-.17-.492-.339-.678-.78-.678H4.593C4.085 7 4 7.237 4 7.491c0 .458.593 2.762 2.762 5.813 1.44 2.084 3.49 3.202 5.338 3.202 1.118 0 1.254-.254 1.254-.678v-1.575c0-.509.101-.594.457-.594.254 0 .712.136 1.746 1.136 1.186 1.186 1.39 1.728 2.05 1.728h1.745c.509 0 .746-.254.61-.745-.152-.492-.728-1.203-1.474-2.05-.407-.475-1.017-1-1.203-1.255-.254-.339-.186-.474 0-.78-.017 0 2.118-3.015 2.338-4.032' fill='%23000' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__item_service_whatsapp .ya-share2__badge,
.ya-share2__item_service_whatsapp .ya-share2__mobile-popup-badge
{
    background-color: #65bc54;
}

.ya-share2__item_service_whatsapp .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M20 11.794c0 4.304-3.517 7.794-7.855 7.794a7.87 7.87 0 01-3.796-.97L4 20l1.418-4.182a7.714 7.714 0 01-1.127-4.024C4.29 7.489 7.807 4 12.145 4S20 7.49 20 11.794zm-7.855-6.553c-3.641 0-6.603 2.94-6.603 6.553A6.48 6.48 0 006.8 15.636l-.825 2.433 2.537-.806a6.6 6.6 0 003.633 1.084c3.642 0 6.604-2.94 6.604-6.553s-2.962-6.553-6.604-6.553zm3.967 8.348c-.049-.08-.177-.128-.37-.223-.192-.095-1.139-.558-1.315-.621-.177-.064-.305-.096-.434.095a10.92 10.92 0 01-.61.749c-.112.128-.224.143-.416.048-.193-.096-.813-.297-1.549-.948a5.76 5.76 0 01-1.07-1.323c-.113-.191-.013-.295.084-.39.086-.086.192-.223.289-.334.096-.112.128-.191.192-.319s.032-.239-.016-.335c-.048-.095-.433-1.035-.594-1.418-.16-.382-.32-.318-.433-.318-.112 0-.24-.016-.369-.016a.71.71 0 00-.513.239c-.177.19-.674.653-.674 1.593s.69 1.848.786 1.976c.096.127 1.332 2.119 3.289 2.884 1.958.764 1.958.51 2.31.477.353-.031 1.14-.461 1.3-.908.16-.446.16-.829.113-.908z' fill='%23FFF' fill-rule='evenodd'/%3E%3C/svg%3E");
}

.ya-share2__container_color-scheme_whiteblack .ya-share2__item_service_whatsapp .ya-share2__icon
{
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M20 11.794c0 4.304-3.517 7.794-7.855 7.794a7.87 7.87 0 01-3.796-.97L4 20l1.418-4.182a7.714 7.714 0 01-1.127-4.024C4.29 7.489 7.807 4 12.145 4S20 7.49 20 11.794zm-7.855-6.553c-3.641 0-6.603 2.94-6.603 6.553A6.48 6.48 0 006.8 15.636l-.825 2.433 2.537-.806a6.6 6.6 0 003.633 1.084c3.642 0 6.604-2.94 6.604-6.553s-2.962-6.553-6.604-6.553zm3.967 8.348c-.049-.08-.177-.128-.37-.223-.192-.095-1.139-.558-1.315-.621-.177-.064-.305-.096-.434.095a10.92 10.92 0 01-.61.749c-.112.128-.224.143-.416.048-.193-.096-.813-.297-1.549-.948a5.76 5.76 0 01-1.07-1.323c-.113-.191-.013-.295.084-.39.086-.086.192-.223.289-.334.096-.112.128-.191.192-.319s.032-.239-.016-.335c-.048-.095-.433-1.035-.594-1.418-.16-.382-.32-.318-.433-.318-.112 0-.24-.016-.369-.016a.71.71 0 00-.513.239c-.177.19-.674.653-.674 1.593s.69 1.848.786 1.976c.096.127 1.332 2.119 3.289 2.884 1.958.764 1.958.51 2.31.477.353-.031 1.14-.461 1.3-.908.16-.446.16-.829.113-.908z' fill='%23000' fill-rule='evenodd'/%3E%3C/svg%3E");
}
</style><style type="text/css"></style><style type="text/css">#ya-site-form0,#ya-site-form0 .ya-site-form__form,#ya-site-form0 .ya-site-form__input,#ya-site-form0 .ya-site-form__input-text,#ya-site-form0 .ya-site-form__search-precise,#ya-site-form0 .ya-site-form__submit{font-size:12px!important;color:#000!important}#ya-site-form0 .ya-site-form__form-form{display:block;margin:0;padding:0}#ya-site-form0 .ya-site-form__input{margin:0;padding:0}#ya-site-form0 .ya-site-form__search-precise{margin:0}#ya-site-form0 .ya-site-form__search-precise__radio{padding:0}#ya-site-form0 .ya-site-form__gap,#ya-site-form0 .ya-site-form__gap-i,#ya-site-form0 .ya-site-form__logo-img{margin:0;padding:0}#ya-site-form0{margin:0!important;padding:0!important}#ya-site-form0 .ya-site-form__logo-wrap{width:65px;vertical-align:top;border-collapse:collapse}#ya-site-form0 .ya-site-form__logo{display:block;width:52px;margin:0;padding:0 6px 0 0;text-decoration:none}#ya-site-form0 .ya-site-form__logo-img{width:52px;height:21px;border:0!important}#ya-site-form0 .ya-site-form__search-wrap{border-collapse:collapse}#ya-site-form0 .ya-site-form__search{font-size:12px!important;width:100%}#ya-site-form0 .ya-site-form__search-input{padding:6px}#ya-site-form0 .ya-site-form__search-input-layout,#ya-site-form0 .ya-site-form__search-input-layout-l,#ya-site-form0 .ya-site-form__search-input-layout-r{font-size:12px!important;padding:0;vertical-align:middle;border:0;border-collapse:collapse}#ya-site-form0 .ya-site-form__search-input-layout,#ya-site-form0 .ya-site-form__search-input-layout-l{width:100%}#ya-site-form0 .ya-site-form__search-precise{padding:0 18px 5px 6px;text-align:left;vertical-align:top}#ya-site-form0 .ya-site-form__search-precise-i{white-space:nowrap}#ya-site-form0 .ya-site-form__search-precise__radio{width:auto;margin:0 .3em 0 0;vertical-align:middle;background:0 0}#ya-site-form0 .ya-site-form__search-precise__label{margin:0 .4em 0 0;padding:0;vertical-align:middle}#ya-site-form0 .ya-site-form__input-text{width:100%;margin:0!important;cursor:text;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;background-color:#fff;border:1px solid #7f9db9;outline-style:none;-webkit-appearance:textfield}#ya-site-form0 .ya-site-form__input-text_type_hint{background-repeat:no-repeat;background-position:.2em 50%}#ya-site-form0 .ya-site-form__submit{display:block;width:auto;margin:0 0 0 5px}#ya-site-form0 .ya-site-form__arrow-wrap{overflow:hidden;width:30px;padding:0;vertical-align:middle}#ya-site-form0 .ya-site-form__arrow{position:relative}#ya-site-form0 .ya-site-form__arrow-a{position:absolute;top:50%;right:0;width:0;height:0;margin-top:-59px;border:solid transparent;border-width:59px 0 59px 30px;-moz-border-end-style:dotted}#ya-site-form0 .ya-site-form__wrap{width:100%;table-layout:fixed;border-collapse:collapse}#ya-site-form0 .ya-site-form__gap{border:0}#ya-site-form0 .ya-site-form__gap-i{width:9em}#ya-site-form0.ya-site-form_arrow_yes .ya-site-form__search-input{padding-right:0}#ya-site-form0.ya-site-form_logo_left .ya-site-form__logo{margin-top:4px;margin-left:5px}#ya-site-form0.ya-site-form_logo_top .ya-site-form__logo{display:block;margin:6px 0 0 6px}#ya-site-form0 .ya-site-form__submit_type_image{width:19px;height:15px;outline:0;cursor:pointer;border:0}#ya-site-form0 .ya-site-form__submit_type_image { background: url(https://site.yandex.net/v2.0/i/search.png) no-repeat }#ya-site-form0 .ya-site-form__form .ya-site-form__input-text::-webkit-input-placeholder{color:#000000;}#ya-site-form0 .ya-site-form__form .ya-site-form__input-text:-moz-placeholder{color:#000000;}#ya-site-form0 .ya-site-form__form .ya-site-form__input-text::-moz-placeholder{color:#000000;}#ya-site-form0 .ya-site-form__form .ya-site-form__input-text:-ms-input-placeholder{color:#000000;}#ya-site-form0 .ya-site-form__form * { font-size: 12px !important }#ya-site-form0 .ya-site-form__form .ya-site-form__input-text { font-style: normal!important }#ya-site-form0 .ya-site-form__form .ya-site-form__input-text { font-weight: normal!important }#ya-site-form0 .ya-site-form__form .ya-site-form__input-text { color: #000000!important }#ya-site-form0 .ya-site-form__form .ya-site-form__input-text { border-color: #7f9db9!important }#ya-site-form0 .ya-site-form__form .ya-site-form__input-text:focus { border-color: #7f9db9!important }#ya-site-form0 .ya-site-form__form .ya-site-form__input-text { background-color: #ffffff!important }#ya-site-form0 .ya-site-form__search, #ya-site-form0 .ya-site-form__search td, #ya-site-form0 .yaform__precise-i { background-color: transparent !important }#ya-site-form0 .ya-site-form__search-precise__label { color:#000000 !important }#ya-site-form0 .ya-site-form__arrow-a { border-left-color: transparent }</style><link title="Поиск по сайту rus-linux.net" rel="search" type="application/opensearchdescription+xml" href="https://yandex.ru/search/site/opensearch.xml?ShortName=%D0%9F%D0%BE%D0%B8%D1%81%D0%BA%20%D0%BF%D0%BE%20%D1%81%D0%B0%D0%B9%D1%82%D1%83%20rus-linux.net&amp;InputEncoding=utf-8&amp;Image=&amp;Url-results=http%3A%2F%2Frus-linux.net%2Fsearch.html%3Fsearchid%3D2271483%26web%3D0%26text%3D%7BsearchTerms%7D&amp;Url-suggest=https%3A%2F%2Fsitesearch-suggest.yandex.ru%2Fv1%2Fsuggest%3F%26site%3D2271483%26lang%3Dru%26part%3D%7BsearchTerms%7D&amp;Url-opensearchdescr=https%3A%2F%2Fyandex.ru%2Fsearch%2Fsite%2Fopensearch.xml%3FShortName%3D%25D0%259F%25D0%25BE%25D0%25B8%25D1%2581%25D0%25BA%2520%25D0%25BF%25D0%25BE%2520%25D1%2581%25D0%25B0%25D0%25B9%25D1%2582%25D1%2583%2520rus-linux.net%26InputEncoding%3Dutf-8%26Image%3D%26Url-results%3Dhttp%253A%252F%252Frus-linux.net%252Fsearch.html%253Fsearchid%253D2271483%2526web%253D0%2526text%253D%257BsearchTerms%257D%26Url-suggest%3Dhttps%253A%252F%252Fsitesearch-suggest.yandex.ru%252Fv1%252Fsuggest%253F%2526site%253D2271483%2526lang%253Dru%2526part%253D%257BsearchTerms%257D"><script type="text/javascript" charset="utf-8" async="" src="./Advanced Bash-Scripting Guide_files/extra.js.Без названия"></script><style type="text/css">#ya-site-form0 .ya-site-suggest{position:relative;margin:0}#ya-site-form0 .ya-site-suggest-popup{position:absolute;width:100%}#ya-site-form0 .ya-site-suggest__opera-gap{position:absolute;height:25em;border:1px solid transparent}#ya-site-form0 .ya-site-suggest-list{position:absolute;z-index:9999;overflow:hidden;min-width:25em;width:100%;margin-top:-1px;border-collapse:separate;-webkit-box-shadow:0 1px 7px #9a9a9a;-moz-box-shadow:0 1px 7px #9a9a9a;box-shadow:0 1px 7px #9a9a9a;border:1px solid #dedede;border-color:rgba(154,154,154,.4) rgba(154,154,154,.5) rgba(154,154,154,.6);box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}#ya-site-form0 .ya-site-suggest__iframe{position:absolute;z-index:-1;min-width:25em;width:100%;height:100%;background:#fff}#ya-site-form0 .ya-site-suggest-items{font-size:16px;min-width:25em;width:100%;margin:0;padding:0 1px 0 0;list-style:none}#ya-site-form0 .ya-site-suggest-items li{margin:0;padding:0;line-height:normal}#ya-site-form0 .ya-site-suggest-elem{display:block;padding:.25em .3em;cursor:pointer;background:url()}#ya-site-form0 a.ya-site-suggest-elem:link,#ya-site-form0 a.ya-site-suggest-elem:visited{text-decoration:none}html body #ya-site-form0 .ya-site-suggest-elem-link,html body #ya-site-form0 .ya-site-suggest-elem:link{color:#000!important}#ya-site-form0 .ya-site-suggest-elem:hover,html body #ya-site-form0 .ya-site-suggest-elem_state_hover{background:#fef6d7}#ya-site-form0 .ya-site-suggest-elem_nav:hover,#ya-site-form0 .ya-site-suggest-elem_translate:hover{text-decoration:none;color:#000!important}#ya-site-form0 .ya-site-suggest-elem_nav .ya-site-suggest__link{text-decoration:underline;color:#1a3dc1}#ya-site-form0 .ya-site-suggest-elem_translate .ya-site-suggest__link{text-decoration:underline;color:#000}#ya-site-form0 .ya-site-suggest-elem .ya-site-suggest__info{white-space:nowrap;color:#666}#ya-site-form0 .ya-site-suggest-elem_selected{background:#fdedaf}#ya-site-form0 .ya-site-suggest__fact{color:#555}#ya-site-form0 .ya-site-suggest__highlight{font-weight:700}</style><script type="text/javascript" async="" src="./Advanced Bash-Scripting Guide_files/checking.js.Без названия"></script></head>
<body lang="ru" class="oldlib cc_cursor" style="" cz-shortcut-listen="true">




<!--Rating@Mail.ru counter-->
<img id="rmr" src="./Advanced Bash-Scripting Guide_files/counter" border="0" height="1" width="1" alt="Рейтинг@Mail.ru">
<!--// Rating@Mail.ru counter-->

<!--LiveInternet counter--><script type="text/javascript"><!--
new Image().src = "//counter.yadro.ru/hit?r"+
escape(document.referrer)+((typeof(screen)=="undefined")?"":
";s"+screen.width+"*"+screen.height+"*"+(screen.colorDepth?
screen.colorDepth:screen.pixelDepth))+";u"+escape(document.URL)+
";h"+escape(document.title.substring(0,80))+
";"+Math.random();//--></script><!--/LiveInternet-->




	
	<header>
		<div id="inhead">
						<a id="logo" href="http://rus-linux.net/" rel="nofollow" title="Виртуальная энциклопедия Linux по-русски"><img src="./Advanced Bash-Scripting Guide_files/logo.jpg" alt="Виртуальная энциклопедия Linux по-русски"></a>
			<div id="rban">
<!-- правый угол -->

<script async="" src="./Advanced Bash-Scripting Guide_files/f(1).txt"></script>
<!-- rus-linux-top-540х80 -->
<ins class="adsbygoogle" style="display:inline-block;width:540px;height:80px" data-ad-client="ca-pub-0144063130920108" data-ad-slot="3740397368"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>

<!--
<a href="https://z.cdn.ftd.agency/load?o=c&z=1177966712&random=[random]"><img align="right" style="margin: 1px;" src="/rekl/img/Denis/Streams_468x90.gif"></a>
-->
<!-- RotaBan.ru Zone Code 
<div id="rotaban_191116" class="rbrocks rotaban_d93b9b532bea4b0f8d7c5f30dafb2ba3"></div>
 END RotaBan.ru Zone Code -->

</div>		</div>
	</header>


	<ul class="menu_box">
	<li class="lbtn cc_cursor"><a href="http://rus-linux.net/" title="Титульная страница сайта">Новости</a></li>
	<li><a href="http://rus-linux.net/lib.php?name=/MyLDP/index.html" title="Тематический каталог книг и статей, опубликованных на сайте">Библиотека</a></li>
	<li><a href="http://rus-linux.net/lib.php?name=/MyLDP/BOOKS/books.html" title="Е-книги по Линукс для чтения он-лайн">Е-книги</a></li>
	<li><a href="http://rus-linux.net/kos.php?name=/inc/site.html#avtory" title="Авторы и переводчики, их статьи, книги и переводы">Авторское</a></li>
	<li><!--noindex--><a href="http://linux-ru.ru/" rel="nofollow" title="Форум по ОС Linux и свободному ПО">Форум</a><!--/noindex--></li>
	<li><a href="http://rus-linux.net/lib.php?name=/txt/kat-full.html" title="Каталог ссылок на публикации в Сети по ОС GNU/Linux">Каталог ссылок</a></li>
	<li><a href="http://rus-linux.net/lib.php?name=/po/linapp.koi" title="Каталог программного обеспечения для ОС GNU/Linux">Каталог ПО</a></li>
	<li><a href="http://rus-linux.net/kos.php?name=/inc/site.html" title="О сайте">О сайте</a></li>
	<li><a href="http://rus-linux.net/lib.php?name=/sitemap.html" title="Карта сайта">Карта сайта</a></li>
</ul>
	<div id="login_box">
		<div id="login_left">  
		</div>
					<div id="login_right">
			<div class="ya-site-form ya-site-form_bg_transparent ya-site-form_inited_yes" id="ya-site-form0"><div class="ya-site-form__form"><table class="ya-site-form__wrap" cellpadding="0" cellspacing="0"><tbody><tr><td class="ya-site-form__search-wrap"><table class="ya-site-form__search" cellpadding="0" cellspacing="0"><tbody><tr><td class="ya-site-form__search-input cc_cursor"><table class="ya-site-form__search-input-layout"><tbody><tr><td class="ya-site-form__search-input-layout-l"><div class="ya-site-form__input"><input name="text" type="search" value="" class="ya-site-form__input-text cc_cursor" placeholder="Поиск по сайту" autocomplete="off"><div class="ya-site-suggest"><div class="ya-site-suggest-popup" style="display: none;"><i class="ya-site-suggest__opera-gap"></i><div class="ya-site-suggest-list"><div class="ya-site-suggest__iframe"></div><ul class="ya-site-suggest-items"></ul></div></div></div></div></td><td class="ya-site-form__search-input-layout-r"><input class="ya-site-form__submit ya-site-form__submit_type_image" type="button" value=""></td></tr></tbody></table></td></tr><tr><td class="ya-site-form__gap"><div class="ya-site-form__gap-i"></div></td></tr></tbody></table></td></tr></tbody></table></div></div><style type="text/css">.ya-page_js_yes .ya-site-form_inited_no { display: none; }</style>
				<script type="text/javascript">(function(w,d,c){var s=d.createElement('script'),h=d.getElementsByTagName('script')[0],e=d.documentElement;if((' '+e.className+' ').indexOf(' ya-page_js_yes ')===-1){e.className+=' ya-page_js_yes';}s.type='text/javascript';s.async=true;s.charset='utf-8';s.src=(d.location.protocol==='https:'?'https:':'http:')+'//site.yandex.net/v2.0/js/all.js';h.parentNode.insertBefore(s,h);(w[c]||(w[c]=[])).push(function(){Ya.Site.Form.init()})})(window,document,'yandex_site_callbacks');</script>
			</div>
			</div>
	
	<div id="obr"><noscript><div id='mns'></div></noscript></div>

		<div class="column_box">
				<div id="left_col" class="column cc_cursor">
			<div id="left_in" class="eic"> 	<div class="ine">  
	<div class="text_box">
		<h2 class="text_head">Наши партнеры</h2>
		<div class="text_body">
			<div class="center">
				<div class="center">

<hr>
<!-- блок Гугла левая колонка -->
<script async="" src="./Advanced Bash-Scripting Guide_files/f(1).txt"></script>
<!-- rus-lin-sidebar-200x300 -->
<ins class="adsbygoogle" style="display:inline-block;width:200px;height:300px" data-ad-client="ca-pub-0144063130920108" data-ad-slot="2811136886"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>

<hr>
<!-- Текстовые ссылки -->

<!-- Конец текстовых ссылок -->

<hr>
<!-- блок Гугла левая колонка -->
<script async="" src="./Advanced Bash-Scripting Guide_files/f(1).txt"></script>
<!-- rus-lin-sidebar-200x300 -->
<ins class="adsbygoogle" style="display:inline-block;width:200px;height:300px" data-ad-client="ca-pub-0144063130920108" data-ad-slot="2811136886"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>

<hr>
<a href="http://rus-linux.net/lib.php?name=/dtb/books-01.koi"><b>Книги по Linux</b></a> (с отзывами читателей)

</div>
			 </div>
		</div>
	</div>
	</div></div>
		</div>
		<div class="vsep"></div>
				<div class="column">
			<div id="main_in" class="eic"> 	
				<div class="ine cc_cursor">		<div class="text_box">
			<p class="text_head cc_cursor"><strong>Библиотека сайта rus-linux.net</strong></p>
			<div class="text_body">
				<div id="gb_1" class="w100 ac">
<!-- блок Гугла в статьях -->
<script async="" src="./Advanced Bash-Scripting Guide_files/f(1).txt"></script>
<!-- rus-linux-banner-728x90 -->
<ins class="adsbygoogle" style="display:inline-block;width:728px;height:90px" data-ad-client="ca-pub-0144063130920108" data-ad-slot="5262754882"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
	</div>  
	<div class="BOOK cc_cursor">
      <a name="AEN1"></a>

      <div class="TITLEPAGE cc_cursor"><a name="AEN2"></a>
        <h1 class="TITLE cc_cursor">Advanced Bash-Scripting Guide</h1>

        <h2 class="SUBTITLE cc_cursor">Искусство программирования на языке сценариев командной оболочки</h2>

        <a name="AEN5"></a><h3 class="AUTHOR cc_cursor">Автор: Mendel Cooper</h3>

        <div class="AFFILIATION cc_cursor">
          Версия 2.8.7 (22 Августа 2004)<br>

          <div class="ADDRESS">
            <p class="ADDRESS"><code>&lt;<a href="mailto:thegrendel@theriver.com">thegrendel@theriver.com</a>&gt;</code></p>
          </div>
        </div>

        <a name="AEN14"></a><h3 class="AUTHOR">Перевод: Андрей Киселев</h3>

        <div class="AFFILIATION">
          <div class="ADDRESS">
            <p class="ADDRESS cc_cursor"><code class="EMAIL">&lt;<a href="mailto:kis_an@mail.ru">kis_an@mail.ru</a>&gt;</code></p>
          </div>
        </div>

        <div>
          <div class="ABSTRACT cc_cursor">
            <a name="AEN102"></a>

            <p>Данное руководство не предполагает наличие у читателя
            познаний в области программирования на языке сценариев,
            однако, быстро восполняет этот недостаток <span class="emphasis"><em class="EMPHASIS">. . . постепенно, шаг за шагом раскрывая
            мудрость и красоту UNIX</em></span>. Это руководство может
            рассматриваться как учебник, предназначенный для
            самостоятельного изучения или как справочник по
            программированию на shell. Руководство снабжено серией
            хорошо прокомментированных примеров, поскольку <code class="USERINPUT cc_cursor"><strong>лучший путь к изучению языка
            сценариев -- это написание сценариев</strong></code>.</p>

            <p>Последнюю версию документа, в виде <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BZIPREF">.bz2</a> архива, содержащем исходные
            тексты в формате SGML и HTML, вы найдете на <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html" "http:="" personal.riverusers.com="" ~thegrendel="" abs-guide-1.8.tar.bz2"="" target="_top">домашней страничке автора</a>. Там же вы
            найдете и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html" "http:="" personal.riverusers.com="" ~thegrendel="" change.log"="" target="_top">change log</a>.</p>
          </div>
        </div>
        <hr>
      </div>
      <hr>

      <h1><a name="AEN110"></a>Посвящения</h1>

      <p>Посвящается Аните -- источнику очарования</p>

      <div class="TOC">
        <dl>
          <dt><strong>Содержание</strong></dt>

          <dt>Часть 1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PART1">Введение</a></dt>

          <dd>
            <dl>
              <dt>1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WHY-SHELL">Зачем необходимо знание языка
              Shell?</a></dt>

              <dt>2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SHA-BANG">Для начала о Sha-Bang</a></dt>

              <dd>
                <dl>
                  <dt>2.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#INVOKING">Запуск сценария</a></dt>

                  <dt>2.2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PRELIMEXER">Упражнения</a></dt>
                </dl>
              </dd>
            </dl>
          </dd>

          <dt>Часть 2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PART2">Основы</a></dt>

          <dd>
            <dl>
              <dt>3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SPECIAL-CHARS">Служебные символы</a></dt>

              <dt>4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#VARIABLES">Переменные и параметры.
              Введение.</a></dt>

              <dd>
                <dl>
                  <dt>4.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#VARSUBN">Подстановка переменных</a></dt>

                  <dt>4.2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#VARASSIGNMENT">Присваивание значений
                  переменным</a></dt>

                  <dt>4.3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#UNTYPED">Переменные Bash не имеют
                  типа</a></dt>

                  <dt>4.4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#OTHERTYPESV">Специальные типы
                  переменных</a></dt>
                </dl>
              </dd>

              <dt>5. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#QUOTING">Кавычки</a></dt>

              <dt>6. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXIT-STATUS">Завершение и код завершения</a></dt>

              <dt>7. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TESTS">Проверка условий</a></dt>

              <dd>
                <dl>
                  <dt>7.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TESTCONSTRUCTS">Конструкции проверки
                  условий</a></dt>

                  <dt>7.2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTO">Операции проверки файлов</a></dt>

                  <dt>7.3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COMPARISON-OPS">Операции сравнения</a></dt>

                  <dt>7.4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#NESTEDIFTHEN">Вложенные условные операторы
                  if/then</a></dt>

                  <dt>7.5. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TESTTEST">Проверка степени усвоения
                  материала</a></dt>
                </dl>
              </dd>

              <dt>8. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#OPERATIONS">Операции и смежные темы</a></dt>

              <dd>
                <dl>
                  <dt>8.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#OPS">Операторы</a></dt>

                  <dt>8.2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#NUMERICAL-CONSTANTS">Числовые
                  константы</a></dt>
                </dl>
              </dd>
            </dl>
          </dd>

          <dt>Часть 3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PART3">Углубленный материал</a></dt>

          <dd>
            <dl>
              <dt>9. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#VARIABLES2">К вопросу о переменных</a></dt>

              <dd>
                <dl>
                  <dt>9.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#INTERNALVARIABLES">Внутренние
                  переменные</a></dt>

                  <dt>9.2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#STRING-MANIPULATION">Работа со
                  строками</a></dt>

                  <dt>9.3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PARAMETER-SUBSTITUTION">Подстановка
                  параметров</a></dt>

                  <dt>9.4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DECLAREREF">Объявление переменных: <strong class="COMMAND">declare</strong> и <strong class="COMMAND">typeset</strong></a></dt>

                  <dt>9.5. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IVR">Косвенные ссылки на переменные</a></dt>

                  <dt>9.6. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RANDOMVAR">$RANDOM: генерация псевдослучайных
                  целых чисел</a></dt>

                  <dt>9.7. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DBLPARENS">Двойные круглые скобки</a></dt>
                </dl>
              </dd>

              <dt>10. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LOOPS">Циклы и ветвления</a></dt>

              <dd>
                <dl>
                  <dt>10.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LOOPS1">Циклы</a></dt>

                  <dt>10.2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#NESTEDLOOPS">Вложенные циклы</a></dt>

                  <dt>10.3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LOOPCONTROL">Управление ходом выполнения
                  цикла</a></dt>

                  <dt>10.4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TESTBRANCH">Операторы выбора</a></dt>
                </dl>
              </dd>

              <dt>11. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#INTERNAL">Внутренние команды</a></dt>

              <dd>
                <dl>
                  <dt>11.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN6110">Команды управления
                  заданиями</a></dt>
                </dl>
              </dd>

              <dt>12. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXTERNAL">Внешние команды, программы и
              утилиты</a></dt>

              <dd>
                <dl>
                  <dt>12.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BASIC">Базовые команды</a></dt>

                  <dt>12.2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MOREADV">Более сложные команды</a></dt>

                  <dt>12.3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TIMEDATE">Команды для работы с датой и
                  временем</a></dt>

                  <dt>12.4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TEXTPROC">Команды обработки текста</a></dt>

                  <dt>12.5. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FILEARCHIV">Команды для работы с файлами и
                  архивами</a></dt>

                  <dt>12.6. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COMMUNICATIONS">Команды для работы с
                  сетью</a></dt>

                  <dt>12.7. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TERMINALCCMDS">Команды управления
                  терминалом</a></dt>

                  <dt>12.8. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MATHC">Команды выполнения математических
                  операций</a></dt>

                  <dt>12.9. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXTMISC">Прочие команды</a></dt>
                </dl>
              </dd>

              <dt>13. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SYSTEM">Команды системного
              администрирования</a></dt>

              <dt>14. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COMMANDSUB">Подстановка команд</a></dt>

              <dt>15. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ARITHEXP">Арифметические подстановки</a></dt>

              <dt>16. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IO-REDIRECTION">Перенаправление
              ввода/вывода</a></dt>

              <dd>
                <dl>
                  <dt>16.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN11702">С помощью команды <strong class="COMMAND">exec</strong></a></dt>

                  <dt>16.2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REDIRCB">Перенаправление для блоков
                  кода</a></dt>

                  <dt>16.3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REDIRAPPS">Область применения</a></dt>
                </dl>
              </dd>

              <dt>17. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#HERE-DOCS">Встроенные документы</a></dt>
            </dl>
          </dd>

          <dt>Часть 4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PART4">Материал повышенной сложности</a></dt>

          <dd>
            <dl>
              <dt>18. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REGEXP">Регулярные выражения</a></dt>

              <dd>
                <dl>
                  <dt>18.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN11904">Краткое введение в регулярные
                  выражения</a></dt>

                  <dt>18.2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GLOBBINGREF">Globbing -- Подстановка имен
                  файлов</a></dt>
                </dl>
              </dd>

              <dt>19. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SUBSHELLS">Подоболочки, или Subshells</a></dt>

              <dt>20. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RESTRICTED-SH">Ограниченный режим командной
              оболочки</a></dt>

              <dt>21. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PROCESS-SUB">Подстановка процессов</a></dt>

              <dt>22. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FUNCTIONS">Функции</a></dt>

              <dd>
                <dl>
                  <dt>22.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COMPLEXFUNCT">Сложные функции и сложности с
                  функциями</a></dt>

                  <dt>22.2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LOCALVAR">Локальные переменные</a></dt>
                </dl>
              </dd>

              <dt>23. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ALIASES">Псевдонимы</a></dt>

              <dt>24. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LIST-CONS">Списки команд</a></dt>

              <dt>25. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ARRAYS">Массивы</a></dt>

              <dt>26. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FILES">Файлы</a></dt>

              <dt>27. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DEVPROC">/dev и /proc</a></dt>

              <dd>
                <dl>
                  <dt>27.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DEVREF1"><code class="FILENAME">/dev</code></a></dt>

                  <dt>27.2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PROCREF1"><code class="FILENAME">/proc</code></a></dt>
                </dl>
              </dd>

              <dt>28. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ZEROS">/dev/zero и /dev/null</a></dt>

              <dt>29. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DEBUGGING">Отладка сценариев</a></dt>

              <dt>30. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#OPTIONS">Необязательные параметры
              (ключи)</a></dt>

              <dt>31. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GOTCHAS">Широко распространенные ошибки</a></dt>

              <dt>32. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SCRSTYLE">Стиль программирования</a></dt>

              <dd>
                <dl>
                  <dt>32.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#UNOFFICIALST">Неофициальные рекомендации по
                  оформлению сценариев</a></dt>
                </dl>
              </dd>

              <dt>33. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MISCELLANY">Разное</a></dt>

              <dd>
                <dl>
                  <dt>33.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#INTANDNONINT">Интерактивный и неинтерактивный
                  режим работы</a></dt>

                  <dt>33.2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WRAPPER">Сценарии-обертки</a></dt>

                  <dt>33.3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TESTSANDCOMPARISONS">Операции сравнения:
                  Альтернативные решения</a></dt>

                  <dt>33.4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RECURSIONSCT">Рекурсия</a></dt>

                  <dt>33.5. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COLORIZING"><span class="QUOTE">"Цветные"</span>
                  сценарии</a></dt>

                  <dt>33.6. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#OPTIMIZATIONS">Оптимизация</a></dt>

                  <dt>33.7. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ASSORTEDTIPS">Разные советы</a></dt>

                  <dt>33.8. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SECURITYISSUES">Проблемы
                  безопасности</a></dt>

                  <dt>33.9. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PORTABILITYISSUES">Проблемы
                  переносимости</a></dt>

                  <dt>33.10. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WINSCRIPT">Сценарии командной оболочки под
                  Windows</a></dt>
                </dl>
              </dd>

              <dt>34. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BASH2">Bash, версия 2</a></dt>
            </dl>
          </dd>

          <dt>35. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ENDNOTES">Замечания и дополнения</a></dt>

          <dd>
            <dl>
              <dt>35.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AUTHORSNOTE">От автора</a></dt>

              <dt>35.2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ABOUTAUTHOR">Об авторе</a></dt>

              <dt>35.3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TOOLSUSED">Инструменты, использовавшиеся при
              создании книги</a></dt>

              <dd>
                <dl>
                  <dt>35.3.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SOFTWARE-HARDWARE">Аппаратура</a></dt>

                  <dt>35.3.2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SOFTWARE-PRINTWARE">Программное
                  обеспечение</a></dt>
                </dl>
              </dd>

              <dt>35.4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CREDITS">Благодарности</a></dt>
            </dl>
          </dd>

          <dt><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BIBLIO">Литература</a></dt>

          <dt>A. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CONTRIBUTED-SCRIPTS">Дополнительные примеры
          сценариев</a></dt>

          <dt>B. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SEDAWK">Маленький учебник по Sed и Awk</a></dt>

          <dd>
            <dl>
              <dt>B.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN14605">Sed</a></dt>

              <dt>B.2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AWK">Awk</a></dt>
            </dl>
          </dd>

          <dt>C. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXITCODES">Коды завершения, имеющие предопределенный
          смысл</a></dt>

          <dt>D. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IOREDIRINTRO">Подробное введение в операции
          ввода-вывода и перенаправление ввода-вывода</a></dt>

          <dt>E. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LOCALIZATION">Локализация</a></dt>

          <dt>F. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#HISTCOMMANDS">История команд</a></dt>

          <dt>G. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SAMPLE-BASHRC">Пример файла <code class="FILENAME">.bashrc</code></a></dt>

          <dt>H. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DOSBATCH">Преобразование пакетных (*.bat) файлов DOS
          в сценарии командной оболочки</a></dt>

          <dt>I. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXERCISES">Упражнения</a></dt>

          <dd>
            <dl>
              <dt>I.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SCRIPTANALYSIS">Анализ сценариев</a></dt>

              <dt>I.2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WRITINGSCRIPTS">Создание сценариев</a></dt>
            </dl>
          </dd>

          <dt>J. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COPYRIGHT">Авторские права</a></dt>
        </dl>
      </div>

      <div class="LOT">
        <dl class="LOT">
          <dt><strong>Перечень таблиц</strong></dt>

          <dt>11-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#JOBIDTABLE">Идентификация заданий</a></dt>

          <dt>30-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN13260">Ключи Bash</a></dt>

          <dt>33-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN13673">Числовые значения цвета в
          escape-последовательностях</a></dt>

          <dt>B-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN14623">Основные операции sed</a></dt>

          <dt>B-2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN14681">Примеры операций в sed</a></dt>

          <dt>C-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN14880"><span class="QUOTE">"Зарезервированные"</span> коды
          завершения</a></dt>

          <dt>H-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN15143">Ключевые слова/переменные/операторы
          пакетных файлов DOS и их аналоги командной оболочки</a></dt>

          <dt>H-2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN15350">Команды DOS и их эквиваленты в
          UNIX</a></dt>
        </dl>
      </div>

      <div class="LOT">
        <dl class="LOT">
          <dt><strong>Перечень приложений</strong></dt>

          <dt>2-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX1"><strong class="COMMAND">cleanup</strong>: Сценарий очистки
          лог-файлов в /var/log</a></dt>

          <dt>2-2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX2"><strong class="COMMAND">cleanup</strong>: Расширенная версия
          предыдущего сценария.</a></dt>

          <dt>3-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX8">Вложенные блоки и перенаправление
          ввода-вывода</a></dt>

          <dt>3-2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RPMCHECK">Сохранение результата исполнения вложенного
          блока в файл</a></dt>

          <dt>3-3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BGLOOP">Запуск цикла в фоновом режиме</a></dt>

          <dt>3-4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX58">Резервное архивирование всех файлов, которые
          были изменены в течение последних суток</a></dt>

          <dt>4-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX9">Присваивание значений переменным и подстановка
          значений переменных</a></dt>

          <dt>4-2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX15">Простое присваивание</a></dt>

          <dt>4-3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX16">Присваивание значений переменным простое и
          замаскированное</a></dt>

          <dt>4-4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#INTORSTRING">Целое число или строка?</a></dt>

          <dt>4-5. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX17">Позиционные параметры</a></dt>

          <dt>4-6. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX18"><strong class="COMMAND">wh</strong>,</a> <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WHOISREF">whois</a> выяснение имени домена</dt>

          <dt>4-7. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX19">Использование команды <strong class="COMMAND">shift</strong></a></dt>

          <dt>5-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WEIRDVARS">Вывод "причудливых"
          переменных</a></dt>

          <dt>5-2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ESCAPED">Экранированные символы</a></dt>

          <dt>6-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX5">завершение / код завершения</a></dt>

          <dt>6-2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#NEGCOND">Использование символа <span class="TOKEN">!</span> для логической инверсии кода
          возврата</a></dt>

          <dt>7-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX10">Что есть "истина"?</a></dt>

          <dt>7-2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX11">Эквиваленты команды <span class="TOKEN">test</span> -- <code class="FILENAME">/usr/bin/test</code>, <span class="TOKEN">[ ]</span>, и <code class="FILENAME">/usr/bin/[</code></a></dt>

          <dt>7-3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ARITHTESTS">Арифметические выражения внутри <span class="TOKEN">(( ))</span></a></dt>

          <dt>7-4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BROKENLINK">Проверка "битых"
          ссылок</a></dt>

          <dt>7-5. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX13">Операции сравнения</a></dt>

          <dt>7-6. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#STRTEST">Проверка -- является ли строка <span class="emphasis"><em class="EMPHASIS">пустой</em></span></a></dt>

          <dt>7-7. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX14"><strong class="COMMAND">zmost</strong></a></dt>

          <dt>8-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GCD">Наибольший общий делитель</a></dt>

          <dt>8-2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ARITHOPS">Арифметические операции</a></dt>

          <dt>8-3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ANDOR">Построение сложных условий, использующих
          &amp;&amp; и ||</a></dt>

          <dt>8-4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#NUMBERS">Различные представления числовых
          констант</a></dt>

          <dt>9-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IFSH">$IFS и пробельные символы</a></dt>

          <dt>9-2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TMDIN">Ограничения времени ожидания ввода</a></dt>

          <dt>9-3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TIMEOUT">Еще один пример ограничения времени ожидания
          ввода от пользователя</a></dt>

          <dt>9-4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TOUT">Ограничение времени ожидания команды <strong class="COMMAND">read</strong></a></dt>

          <dt>9-5. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AMIROOT">Я -- root?</a></dt>

          <dt>9-6. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ARGLIST"><strong class="COMMAND">arglist</strong>: Вывод списка аргументов с
          помощью переменных $* и $@</a></dt>

          <dt>9-7. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#INCOMPAT">Противоречия в переменных <code class="VARNAME">$*</code> и <code class="VARNAME">$@</code></a></dt>

          <dt>9-8. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IFSEMPTY">Содержимое <code class="VARNAME">$*</code> и <code class="VARNAME">$@</code>, когда переменная <code class="VARNAME cc_pointer">$IFS</code> -- пуста</a></dt>

          <dt>9-9. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#USCREF">Переменная "подчеркивание"</a></dt>

          <dt>9-10. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PARAGRAPHSPACE">Вставка пустых строк между
          параграфами в текстовом файле</a></dt>

          <dt>9-11. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CVT">Преобразование графических файлов из одного
          формата в другой, с изменением имени файла</a></dt>

          <dt>9-12. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SUBSTRINGEX">Альтернативный способ извлечения
          подстрок</a></dt>

          <dt>9-13. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX6">Подстановка параметров и сообщения об
          ошибках</a></dt>

          <dt>9-14. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#USAGEMESSAGE">Подстановка параметров и сообщение о
          <span class="QUOTE">"порядке
          использования"</span></a></dt>

          <dt>9-15. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LENGTH">Длина переменной</a></dt>

          <dt>9-16. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PATTMATCHING">Поиск по шаблону в подстановке
          параметров</a></dt>

          <dt>9-17. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RFE">Изменение расширений в именах файлов<span class="TOKEN">:</span></a></dt>

          <dt>9-18. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX7">Поиск по шаблону при анализе произвольных
          строк</a></dt>

          <dt>9-19. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#VARMATCH">Поиск префиксов и суффиксов с заменой по
          шаблону</a></dt>

          <dt>9-20. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX20">Объявление переменных с помощью инструкции
          <strong class="COMMAND">declare</strong></a></dt>

          <dt>9-21. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#INDREF">Косвенные ссылки</a></dt>

          <dt>9-22. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COLTOTALER2">Передача косвенных ссылок в <code class="REPLACEABLE"><em>awk</em></code></a></dt>

          <dt>9-23. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX21">Генерация случайных чисел</a></dt>

          <dt>9-24. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PICKCARD">Выбор случайной карты из колоды</a></dt>

          <dt>9-25. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RANDOMTEST">Имитация бросания кубика с помощью
          RANDOM</a></dt>

          <dt>9-26. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SEEDINGRANDOM">Переустановка RANDOM</a></dt>

          <dt>9-27. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RANDOM2">Получение псевдослучайных чисел с
          помощью</a> <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AWKREF">awk</a></dt>

          <dt>9-28. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CVARS">Работа с переменными в стиле языка C</a></dt>

          <dt>10-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX22">Простой цикл <strong class="COMMAND">for</strong></a></dt>

          <dt>10-2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX22A">Цикл <strong class="COMMAND">for</strong> с двумя параметрами в каждом из
          элементов списка</a></dt>

          <dt>10-3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FILEINFO"><span class="emphasis"><em class="EMPHASIS">Fileinfo:</em></span> обработка списка
          файлов, находящегося в переменной</a></dt>

          <dt>10-4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LISTGLOB">Обработка списка файлов в цикле <strong class="COMMAND">for</strong></a></dt>

          <dt>10-5. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX23">Цикл <strong class="COMMAND">for</strong> без списка аргументов</a></dt>

          <dt>10-6. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FORLOOPCMD">Создание списка аргументов в цикле
          <strong class="COMMAND">for</strong> с помощью операции подстановки
          команд</a></dt>

          <dt>10-7. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BINGREP"></a><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GREPREF">grep</a> для бинарных файлов</dt>

          <dt>10-8. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#USERLIST">Список всех пользователей системы</a></dt>

          <dt>10-9. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FINDSTRING">Проверка авторства всех бинарных файлов в
          текущем каталоге</a></dt>

          <dt>10-10. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SYMLINKS">Список символических ссылок в
          каталоге</a></dt>

          <dt>10-11. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SYMLINKS2">Список символических ссылок в каталоге,
          сохраняемый в файле</a></dt>

          <dt>10-12. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FORLOOPC">C-подобный синтаксис оператора цикла
          <strong class="COMMAND">for</strong></a></dt>

          <dt>10-13. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX24">Работа с командой <strong class="COMMAND">efax</strong> в пакетном режиме</a></dt>

          <dt>10-14. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX25">Простой цикл <strong class="COMMAND">while</strong></a></dt>

          <dt>10-15. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX26">Другой пример цикла <strong class="COMMAND">while</strong></a></dt>

          <dt>10-16. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX26A">Цикл <strong class="COMMAND">while</strong> с несколькими
          условиями</a></dt>

          <dt>10-17. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WHLOOPC">C-подобный синтаксис оформления цикла
          <strong class="COMMAND">while</strong></a></dt>

          <dt>10-18. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX27">Цикл <strong class="COMMAND">until</strong></a></dt>

          <dt>10-19. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#NESTEDLOOP">Вложенный цикл</a></dt>

          <dt>10-20. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX28">Команды <strong class="COMMAND">break</strong> и <strong class="COMMAND">continue</strong> в цикле</a></dt>

          <dt>10-21. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BREAKLEVELS">Прерывание многоуровневых
          циклов</a></dt>

          <dt>10-22. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CONTINUELEVELS">Передача управление в начало внешнего
          цикла</a></dt>

          <dt>10-23. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CONTINUENEX">Живой пример использования <span class="QUOTE">"continue N"</span></a></dt>

          <dt>10-24. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX29">Использование <strong class="COMMAND">case</strong></a></dt>

          <dt>10-25. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX30">Создание меню с помощью <strong class="COMMAND">case</strong></a></dt>

          <dt>10-26. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CASECMD">Оператор <strong class="COMMAND cc_pointer">case</strong> допускает использовать
          подстановку команд вместо анализируемой переменной</a></dt>

          <dt>10-27. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MATCHSTRING">Простой пример сравнения строк</a></dt>

          <dt>10-28. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ISALPHA">Проверка ввода</a></dt>

          <dt>10-29. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX31">Создание меню с помощью <strong class="COMMAND">select</strong></a></dt>

          <dt>10-30. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX32">Создание меню с помощью <strong class="COMMAND">select</strong> в функции</a></dt>

          <dt>11-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX47"><strong class="COMMAND">printf</strong> в действии</a></dt>

          <dt>11-2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX36">Ввод значений переменных с помощью <strong class="COMMAND">read</strong></a></dt>

          <dt>11-3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#READNOVAR">Пример использования команды <strong class="COMMAND">read</strong> без указания переменной для
          ввода</a></dt>

          <dt>11-4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#READR">Ввод многострочного текста с помощью <strong class="COMMAND">read</strong></a></dt>

          <dt>11-5. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ARROWDETECT">Обнаружение нажатия на курсорные
          клавиши</a></dt>

          <dt>11-6. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#READREDIR">Чтение командой <strong class="COMMAND">read</strong> из файла через</a> <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IOREDIRREF">перенаправление</a></dt>

          <dt>11-7. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX37">Смена текущего каталога</a></dt>

          <dt>11-8. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX46">Команда <strong class="COMMAND">let</strong>, арифметические
          операции.</a></dt>

          <dt>11-9. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX43">Демонстрация команды <strong class="COMMAND">eval</strong></a></dt>

          <dt>11-10. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX44">Принудительное завершение сеанса</a></dt>

          <dt>11-11. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ROT14">Шифрование по алгоритму <span class="QUOTE">"rot13"</span></a></dt>

          <dt>11-12. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EVALEX">Замена имени переменной на ее значение, в
          исходном тексте программы на языке Perl, с помощью <strong class="COMMAND">eval</strong></a></dt>

          <dt>11-13. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX34">Установка значений аргументов с помощью команды
          <strong class="COMMAND">set</strong></a></dt>

          <dt>11-14. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SETPOS">Изменение значений позиционных параметров
          (аргументов)</a></dt>

          <dt>11-15. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#UNS"><span class="QUOTE">"Сброс"</span> переменной</a></dt>

          <dt>11-16. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COLTOTALER3">Передача переменных во вложенный
          сценарий</a> <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AWKREF">awk</a>, с помощью <strong class="COMMAND">export</strong></dt>

          <dt>11-17. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX33">Прием опций/аргументов, передаваемых сценарию,
          с помощью <strong class="COMMAND">getopts</strong></a></dt>

          <dt>11-18. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX38"><span class="QUOTE">"Подключение"</span> внешнего
          файла</a></dt>

          <dt>11-19. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SELFSOURCE">Пример (бесполезный) сценария, который
          подключает себя самого.</a></dt>

          <dt>11-20. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX54">Команда <strong class="COMMAND">exec</strong></a></dt>

          <dt>11-21. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SELFEXEC">Сценарий, который запускает себя
          самого</a></dt>

          <dt>11-22. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX39">Ожидание завершения процесса перед тем как
          продолжить работу</a></dt>

          <dt>11-23. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SELFDESTRUCT">Сценарий, завершающий себя сам с
          помощью команды kill</a></dt>

          <dt>12-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX40">Создание оглавления диска для записи <span class="ABBREV">CDR</span>, с помощью команды <strong class="COMMAND">ls</strong></a></dt>

          <dt>12-2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX57"><strong class="COMMAND">Badname</strong>, удаление файлов в текущем
          каталоге, имена которых содержат недопустимые символы и</a>
          <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WHITESPACEREF">пробелы</a>.</dt>

          <dt>12-3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IDELETE">Удаление файла по его номеру <span class="emphasis"><em class="EMPHASIS">inode</em></span></a></dt>

          <dt>12-4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX41">Использование команды <strong class="COMMAND">xargs</strong> для мониторинга системного
          журнала</a></dt>

          <dt>12-5. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX42"><strong class="COMMAND">copydir</strong>, копирование файлов из
          текущего каталога в другое место, с помощью <strong class="COMMAND">xargs</strong></a></dt>

          <dt>12-6. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX45">Пример работы с <strong class="COMMAND">expr</strong></a></dt>

          <dt>12-7. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX51">Команда <strong class="COMMAND">date</strong></a></dt>

          <dt>12-8. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WF">Частота встречаемости отдельных слов</a></dt>

          <dt>12-9. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SCRIPTDETECTOR">Какие из файлов являются
          сценариями?</a></dt>

          <dt>12-10. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RND">Генератор 10-значных случайных чисел</a></dt>

          <dt>12-11. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX12">Мониторинг системного журнала с помощью <strong class="COMMAND">tail</strong></a></dt>

          <dt>12-12. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GRP">Сценарий-эмулятор <span class="QUOTE">"grep"</span></a></dt>

          <dt>12-13. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LOOKUP">Поиск слов в словаре</a></dt>

          <dt>12-14. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX49"><strong class="COMMAND">toupper</strong>: Преобразование символов в
          верхний регистр.</a></dt>

          <dt>12-15. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LOWERCASE"><strong class="COMMAND">lowercase</strong>: Изменение имен всех
          файлов в текущем каталоге в нижний регистр.</a></dt>

          <dt>12-16. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DU"><strong class="COMMAND">du</strong>: Преобразование текстового файла
          из формата DOS в формат UNIX.</a></dt>

          <dt>12-17. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ROT13"><strong class="COMMAND">rot13</strong>: Сверхслабое шифрование по
          алгоритму rot13.</a></dt>

          <dt>12-18. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CRYPTOQUOTE">Более <span class="QUOTE">"сложный"</span> шифр</a></dt>

          <dt>12-19. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX50">Отформатированный список файлов.</a></dt>

          <dt>12-20. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COL">Пример форматирования списка файлов в
          каталоге</a></dt>

          <dt>12-21. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LNUM"><strong class="COMMAND">nl</strong>: Самонумерующийся
          сценарий.</a></dt>

          <dt>12-22. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX48">Пример перемещения дерева каталогов с помощью
          <strong class="COMMAND">cpio</strong></a></dt>

          <dt>12-23. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DERPM">Распаковка архива <span class="emphasis"><em class="EMPHASIS">rpm</em></span></a></dt>

          <dt>12-24. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#STRIPC">Удаление комментариев из файла с текстом
          программы на языке C</a></dt>

          <dt>12-25. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WHAT"><strong class="COMMAND">Исследование каталога <code class="FILENAME">/usr/X11R6/bin</code></strong></a></dt>

          <dt>12-26. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WSTRINGS"><span class="QUOTE">"Расширенная"</span> команда <span class="emphasis"><em class="EMPHASIS">strings</em></span></a></dt>

          <dt>12-27. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FILECOMP">Пример сравнения двух файлов с помощью
          <strong class="COMMAND">cmp</strong>.</a></dt>

          <dt>12-28. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX35">Утилиты <strong class="COMMAND">basename</strong> и <strong class="COMMAND">dirname</strong></a></dt>

          <dt>12-29. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FILEINTEGRITY">Проверка целостности файла</a></dt>

          <dt>12-30. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX52">Декодирование файлов</a></dt>

          <dt>12-31. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SELFMAILER">Сценарий, отправляющий себя самого по
          электронной почте</a></dt>

          <dt>12-32. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MONTHLYPMT">Ежемесячные выплаты по займу</a></dt>

          <dt>12-33. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BASE">Перевод чисел из одной системы счисления в
          другую</a></dt>

          <dt>12-34. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ALTBC">Пример взаимодействия <strong class="COMMAND">bc</strong> со <span class="QUOTE">"встроенным
          документом"</span></a></dt>

          <dt>12-35. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CANNON">Вычисление числа "пи"</a></dt>

          <dt>12-36. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#HEXCONVERT">Преобразование чисел из десятичной в
          шестнадцатиричную систему счисления</a></dt>

          <dt>12-37. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FACTR">Разложение числа на простые множители</a></dt>

          <dt>12-38. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#HYPOT">Расчет гипотенузы прямоугольного
          треугольника</a></dt>

          <dt>12-39. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX53">Использование <strong class="COMMAND">seq</strong> для генерации списка аргументов
          цикла for</a></dt>

          <dt>12-40. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX33A">Использование <strong class="COMMAND">getopt</strong> для разбора аргументов
          командной строки</a></dt>

          <dt>12-41. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DDKEYPRESS">Захват нажатых клавиш</a></dt>

          <dt>12-42. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BLOTOUT">Надежное удаление файла</a></dt>

          <dt>12-43. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TEMPFILENAME">Генератор имен файлов</a></dt>

          <dt>12-44. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#UNITCONVERSION">Преобразование метров в мили</a></dt>

          <dt>12-45. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#M4">Пример работы с m4</a></dt>

          <dt>13-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ERASE">Установка символа "забоя"</a></dt>

          <dt>13-2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SECRETPW"><strong class="COMMAND">невидимый пароль</strong>: Отключение
          эхо-вывода на терминал</a></dt>

          <dt>13-3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#KEYPRESS"></a></dt>

          <dt>13-4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#KILLPROCESS">Использование команды <strong class="COMMAND">pidof</strong> при остановке
          процесса</a></dt>

          <dt>13-5. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ISOMOUNTREF">Проверка образа CD</a></dt>

          <dt>13-6. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CREATEFS">Создание файловой системы в обычном
          файле</a></dt>

          <dt>13-7. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ADDDRV">Добавление нового жесткого диска</a></dt>

          <dt>13-8. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX55">Сценарий <strong class="COMMAND">killall</strong>, из каталога <code class="FILENAME">/etc/rc.d/init.d</code></a></dt>

          <dt>14-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#STUPSCR">Глупая выходка</a></dt>

          <dt>14-2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CSUBLOOP">Запись результатов выполнения цикла в
          переменную</a></dt>

          <dt>16-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REDIR1">Перенаправление <code class="FILENAME">stdin</code> с помощью <strong class="COMMAND">exec</strong></a></dt>

          <dt>16-2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REASSIGNSTDOUT">Перенаправление <code class="FILENAME">stdout</code> с помощью <strong class="COMMAND">exec</strong></a></dt>

          <dt>16-3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#UPPERCONV">Одновременное перенаправление устройств,
          <code class="FILENAME">stdin</code> и <code class="FILENAME">stdout</code>, с помощью команды <strong class="COMMAND">exec</strong></a></dt>

          <dt>16-4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REDIR2">Перенаправление в цикл <span class="emphasis"><em class="EMPHASIS">while</em></span></a></dt>

          <dt>16-5. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REDIR2A">Альтернативная форма перенаправления в цикле
          <span class="emphasis"><em class="EMPHASIS">while</em></span></a></dt>

          <dt>16-6. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REDIR3">Перенаправление в цикл <span class="emphasis"><em class="EMPHASIS">until</em></span></a></dt>

          <dt>16-7. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REDIR4">Перенаправление в цикл <span class="emphasis"><em class="EMPHASIS">for</em></span></a></dt>

          <dt>16-8. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REDIR4A">Перенаправление устройств (<code class="FILENAME">stdin</code> и <code class="FILENAME">stdout</code>) в цикле <span class="emphasis"><em class="EMPHASIS">for</em></span></a></dt>

          <dt>16-9. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REDIR5">Перенаправление в конструкции <span class="emphasis"><em class="EMPHASIS">if/then</em></span></a></dt>

          <dt>16-10. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#NAMESDATA">Файл с именами <span class="QUOTE">"names.data"</span>, для примеров
          выше</a></dt>

          <dt>16-11. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LOGEVENTS">Регистрация событий</a></dt>

          <dt>17-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX69"><strong class="COMMAND">dummyfile</strong>: Создание 2-х строчного
          файла-заготовки</a></dt>

          <dt>17-2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX70"><strong class="COMMAND">broadcast</strong>: Передача сообщения всем,
          работающим в системе, пользователям</a></dt>

          <dt>17-3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX71">Вывод многострочных сообщений с помощью <strong class="COMMAND">cat</strong></a></dt>

          <dt>17-4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX71A">Вывод многострочных сообщений с подавлением
          символов табуляции</a></dt>

          <dt>17-5. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX71B">Встроенные документы и подстановка
          параметров</a></dt>

          <dt>17-6. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX71C">Отключение подстановки параметров</a></dt>

          <dt>17-7. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX72">Передача пары файлов во входящий каталог на
          <span class="QUOTE">"Sunsite"</span></a></dt>

          <dt>17-8. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#HF">Встроенные документы и функции</a></dt>

          <dt>17-9. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ANONHEREDOC"><span class="QUOTE">"Анонимный"</span> Встроенный
          Документ</a></dt>

          <dt>17-10. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COMMENTBLOCK">Блочный комментарий</a></dt>

          <dt>17-11. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SELFDOCUMENT">Встроенная справка к сценарию</a></dt>

          <dt>19-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SUBSHELL">Область видимости переменных</a></dt>

          <dt>19-2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ALLPROFS">Личные настройки пользователей</a></dt>

          <dt>19-3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PARALLEL-PROCESSES">Запуск нескольких процессов в
          подоболочках</a></dt>

          <dt>20-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RESTRICTED">Запуск сценария в ограниченном
          режиме</a></dt>

          <dt>22-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX59">Простая функция</a></dt>

          <dt>22-2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX60">Функция с аргументами</a></dt>

          <dt>22-3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MAX">Наибольшее из двух чисел</a></dt>

          <dt>22-4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX61">Преобразование чисел в римскую форму
          записи</a></dt>

          <dt>22-5. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RETURNTEST">Проверка возможности возврата функциями
          больших значений</a></dt>

          <dt>22-6. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MAX2">Сравнение двух больших целых чисел</a></dt>

          <dt>22-7. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REALNAME">Настоящее имя пользователя</a></dt>

          <dt>22-8. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX62">Область видимости локальных переменных</a></dt>

          <dt>22-9. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX63">Использование локальных переменных при
          рекурсии</a></dt>

          <dt>23-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AL">Псевдонимы в сценарии</a></dt>

          <dt>23-2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#UNAL"><strong class="COMMAND">unalias</strong>: Объявление и удаление
          псевдонимов</a></dt>

          <dt>24-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX64">Проверка аргументов командной строки с помощью
          <span class="QUOTE">"И-списка"</span></a></dt>

          <dt>24-2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ANDLIST2">Еще один пример проверки аргументов с
          помощью <span class="QUOTE">"И-списков"</span></a></dt>

          <dt>24-3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX65">Комбинирование <span class="QUOTE">"ИЛИ-списков"</span> и <span class="QUOTE">"И-списков"</span></a></dt>

          <dt>25-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX66">Простой массив</a></dt>

          <dt>25-2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#POEM">Форматирование стихотворения</a></dt>

          <dt>25-3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX67">Некоторые специфичные особенности
          массивов</a></dt>

          <dt>25-4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EMPTYARRAY">Пустые массивы и пустые элементы</a></dt>

          <dt>25-5. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COPYARRAY">Копирование и конкатенация
          массивов</a></dt>

          <dt>25-6. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BUBBLE">Старая, добрая: <span class="emphasis"><em class="EMPHASIS">"Пузырьковая"
          сортировка</em></span></a></dt>

          <dt>25-7. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EMBARR">Вложенные массивы и косвенные ссылки</a></dt>

          <dt>25-8. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX68">Пример реализации алгоритма <span class="emphasis"><em class="EMPHASIS">Решето Эратосфена</em></span></a></dt>

          <dt>25-9. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#STACKEX">Эмуляция структуры "СТЕК"
          ("первый вошел -- последний вышел")</a></dt>

          <dt>25-10. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#QFUNCTION"><span class="emphasis"><em class="EMPHASIS">Исследование математических
          последовательностей</em></span></a></dt>

          <dt>25-11. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TWODIM">Эмуляция массива с двумя измерениями</a></dt>

          <dt>27-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PIDID">Поиск файла программы по идентификатору
          процесса</a></dt>

          <dt>27-2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CONSTAT">Проверка состояния соединения</a></dt>

          <dt>28-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COOKIES">Удаление cookie-файлов</a></dt>

          <dt>28-2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX73">Создание файла подкачки (swapfile), с помощью
          <code class="FILENAME">/dev/zero</code></a></dt>

          <dt>28-3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RAMDISK">Создание электронного диска</a></dt>

          <dt>29-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX74">Сценарий, содержащий ошибку</a></dt>

          <dt>29-2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MISSINGKEYWORD">Пропущено</a> <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#KEYWORDREF">ключевое слово</a></dt>

          <dt>29-3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX75">test24</a></dt>

          <dt>29-4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ASSERT">Проверка условия с помощью функции <span class="QUOTE">"assert"</span></a></dt>

          <dt>29-5. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX76">Ловушка на выходе</a></dt>

          <dt>29-6. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ONLINE">Удаление временного файла при нажатии на
          Control-C</a></dt>

          <dt>29-7. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#VARTRACE">Трассировка переменной</a></dt>

          <dt>31-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SUBPIT">Западня в подоболочке</a></dt>

          <dt>31-2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BADREAD">Передача вывода от команды <strong class="COMMAND">echo</strong> команде <strong class="COMMAND">read</strong>, по конвейеру</a></dt>

          <dt>33-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX3"><strong class="COMMAND">сценарий-обертка</strong></a></dt>

          <dt>33-2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX4">Более сложный пример <strong class="COMMAND">сценария-обертки</strong></a></dt>

          <dt>33-3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COLTOTALER"><strong class="COMMAND">Сценарий-обертка</strong> вокруг сценария
          awk</a></dt>

          <dt>33-4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX56">Сценарий на языке Perl, встроенный в <strong class="COMMAND">Bash</strong>-скрипт</a></dt>

          <dt>33-5. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BASHANDPERL">Комбинирование сценария Bash и Perl в
          одном файле</a></dt>

          <dt>33-6. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RECURSE">Сценарий (бесполезный), который вызывает
          себя сам</a></dt>

          <dt>33-7. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PBOOK">Сценарий имеющий практическую ценность),
          который вызывает себя сам</a></dt>

          <dt>33-8. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX30A"><span class="QUOTE">"Цветная"</span> адресная
          книга</a></dt>

          <dt>33-9. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COLORECHO">Вывод цветного текста</a></dt>

          <dt>33-10. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MULTIPLICATION">Необычный способ передачи
          возвращаемого значения</a></dt>

          <dt>33-11. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SUMPRODUCT">Необычный способ получения нескольких
          возвращаемых значений</a></dt>

          <dt>33-12. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ARRFUNC">Передача массива в функцию и возврат массива
          из функции</a></dt>

          <dt>33-13. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AGRAM">Игры с анаграммами</a></dt>

          <dt>34-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX77">Расширение строк</a></dt>

          <dt>34-2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX78">Косвенные ссылки на переменные -- новый
          метод</a></dt>

          <dt>34-3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RESISTOR">Простая база данных, с применением
          косвенных ссылок</a></dt>

          <dt>34-4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX79">Массивы и другие хитрости для раздачи колоды
          карт в четыре руки</a></dt>

          <dt>A-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MANVIEW"><strong class="COMMAND">manview</strong>: Просмотр страниц
          руководств man</a></dt>

          <dt>A-2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MAILFORMAT"><strong class="COMMAND">mailformat</strong>: Форматирование
          электронных писем</a></dt>

          <dt>A-3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RN"><strong class="COMMAND">rn</strong>: Очень простая утилита для
          переименования файлов</a></dt>

          <dt>A-4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BLANKRENAME"><strong class="COMMAND">blank-rename</strong>: переименование
          файлов, чьи имена содержат пробелы</a></dt>

          <dt>A-5. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ENCRYPTEDPW"><strong class="COMMAND">encryptedpw</strong>: Передача файла на
          ftp-сервер, с использованием пароля</a></dt>

          <dt>A-6. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COPYCD"><strong class="COMMAND">copy-cd</strong>: Копирование компакт-дисков
          с данными</a></dt>

          <dt>A-7. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COLLATZ">Последовательности Коллаца
          (Collatz)</a></dt>

          <dt>A-8. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DAYSBETWEEN"><strong class="COMMAND">days-between</strong>: Подсчет числа дней
          между двумя датами</a></dt>

          <dt>A-9. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MAKEDICT">Создание <span class="QUOTE">"словаря"</span></a></dt>

          <dt>A-10. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SOUNDEX">Расчет индекса
          "созвучности"</a></dt>

          <dt>A-11. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LIFESLOW"><span class="QUOTE">"Игра
          "Жизнь""</span></a></dt>

          <dt>A-12. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GEN0DATA">Файл с первым поколением для игры <span class="QUOTE">"Жизнь"</span></a></dt>

          <dt>A-13. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BEHEAD"><strong class="COMMAND">behead</strong>: Удаление заголовков из
          электронных писем и новостей</a></dt>

          <dt>A-14. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTPGET"><strong class="COMMAND">ftpget</strong>: Скачивание файлов по
          ftp</a></dt>

          <dt>A-15. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MORCOPY">Указание на авторские права</a></dt>

          <dt>A-16. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PW"><strong class="COMMAND">password</strong>: Генератор случайного 8-ми
          символьного пароля</a></dt>

          <dt>A-17. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FIFO"><strong class="COMMAND">fifo</strong>: Создание резервных копий с
          помощью именованных каналов</a></dt>

          <dt>A-18. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PRIMES">Генерация простых чисел, с использованием
          оператора деления по модулю (остаток от деления)</a></dt>

          <dt>A-19. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TREE"><strong class="COMMAND">tree</strong>: Вывод дерева
          каталогов</a></dt>

          <dt>A-20. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#STRING"><strong class="COMMAND">Функции для работы со
          строками</strong></a></dt>

          <dt>A-21. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DIRECTORYINFO">Directory information</a></dt>

          <dt>A-22. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#OBJORIENTED">Объектно ориентированная база
          данных</a></dt>

          <dt>G-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BASHRC">Пример файла <code class="FILENAME">.bashrc</code></a></dt>

          <dt>H-1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#VIEWDAT">VIEWDATA.BAT: пакетный файл DOS</a></dt>

          <dt>H-2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#VIEWDATA">viewdata.sh: Результат преобразования
          VIEWDATA.BAT в сценарий командной оболочки</a></dt>
        </dl>
      </div>

      <div class="PART cc_cursor">
        <a name="PART1"></a>

        <div class="TITLEPAGE">
          <h1 class="TITLE">Часть 1. Введение</h1>

          <div class="PARTINTRO">
            <a name="AEN114"></a>

            <p>Shell -- это командная оболочка. Но это не просто
            промежуточное звено между пользователем и операционой
            системой, это еще и мощный язык программирования. Программы
            на языке shell называют <span class="emphasis"><em class="EMPHASIS">сценариями</em></span>, или <span class="emphasis"><em class="EMPHASIS">скриптами</em></span>. Фактически, из
            скриптов доступен полный набор команд, утилит и программ
            UNIX. Если этого недостаточно, то к вашим услугам
            внутренние команды shell -- условные операторы, операторы
            циклов и пр., которые увеличивают мощь и гибкость
            сценариев. Shell-скрипты исключительно хороши при
            программировании задач администрирования системы и др.,
            которые не требуют для своего создания полновесных языков
            программирования.</p>
          </div>

          <div class="TOC">
            <dl>
              <dt><strong>Содержание</strong></dt>

              <dt>1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WHY-SHELL">Зачем необходимо знание языка
              Shell?</a></dt>

              <dt>2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SHA-BANG">Для начала о Sha-Bang</a></dt>

              <dd>
                <dl>
                  <dt>2.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#INVOKING">Запуск сценария</a></dt>

                  <dt>2.2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PRELIMEXER">Упражнения</a></dt>
                </dl>
              </dd>
            </dl>
          </div>
        </div>

        <div class="CHAPTER cc_cursor">
          <hr>

          <h1><a name="WHY-SHELL"></a>Глава 1. Зачем необходимо знание языка
          Shell?</h1>

          <p>Знание языка командной оболочки является залогом успешного
          решения задач администрирования системы. Даже если вы не
          предполагаете заниматься написанием своих сценариев. Во время
          загрузки Linux выполняется целый ряд сценариев из <code class="FILENAME">/etc/rc.d</code>, которые настраивают
          конфигурацию операционной системы и запускают различные
          сервисы, поэтому очень важно четко понимать эти скрипты и
          иметь достаточно знаний, чтобы вносить в них какие либо
          изменения.</p>

          <p>Язык сценариев легок в изучении, в нем не так много
          специфических операторов и конструкций. <a name="AEN123" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN123"><span class="footnote">[1]</span></a> Синтаксис языка достаточно
          прост и прямолинеен, он очень напоминает команды, которые
          приходится вводить в командной строке. Короткие скрипты
          практически не нуждаются в отладке, и даже отладка больших
          скриптов отнимает весьма незначительное время.</p>

          <p>Shell-скрипты очень хорошо подходят для быстрого создания
          прототипов сложных приложений, даже не смотря на ограниченный
          набор языковых конструкций и определенную
          "медлительность". Такая метода позволяет детально
          проработать структуру будущего приложения, обнаружить
          возможные "ловушки" и лишь затем приступить к
          кодированию на C, C++, Java, или Perl.</p>

          <p>Скрипты возвращают нас к классической философии UNIX --
          "разделяй и влавствуй" т.е. разделение сложного
          проекта на ряд простых подзадач. Многие считают такой подход
          наилучшим или, по меньшей мере, наиболее эстетичным способом
          решения возникающих проблем, нежели использование нового
          поколения языков -- "все-в-одном", таких как
          Perl.</p>

          <p>Для каких задач неприменимы скрипты</p>

          <ul>
            <li>
              <p>для ресурсоемких задач, особенно когда важна скорость
              исполнения (поиск, сортировка и т.п.)</p>
            </li>

            <li>
              <p>для задач, связанных с выполнением математических
              вычислений, особенно это касается вычислений с плавающей
              запятой, вычислений с повышенной точностью, комплексных
              чисел (для таких задач лучше использовать C++ или
              FORTRAN)</p>
            </li>

            <li>
              <p>для кросс-платформенного программирования (для этого
              лучше подходит язык C)</p>
            </li>

            <li>
              <p>для сложных приложений, когда структурирование
              является жизненной необходимостью (контроль за типами
              переменных, прототипами функций и т.п.)</p>
            </li>

            <li>
              <p>для целевых задач, от которых может зависеть успех
              предприятия.</p>
            </li>

            <li>
              <p>когда во главу угла поставлена безопасность системы,
              когда необходимо обеспечить целостность системы и
              защитить ее от вторжения, взлома и вандализма.</p>
            </li>

            <li>
              <p>для проектов, содержащих компоненты, очень тесно
              взаимодействующие между собой.</p>
            </li>

            <li>
              <p>для задач, выполняющих огромный объем работ с
              файлами</p>
            </li>

            <li>
              <p>для задач, работающих с многомерными массивами</p>
            </li>

            <li>
              <p>когда необходимо работать со структурами данных,
              такими как связанные списки или деревья</p>
            </li>

            <li>
              <p>когда необходимо предоставить графический интерфейс с
              пользователем (GUI)</p>
            </li>

            <li>
              <p>когда необходим прямой доступ к аппаратуре
              компьютера</p>
            </li>

            <li>
              <p>когда необходимо выполнять обмен через порты
              ввода-вывода или сокеты</p>
            </li>

            <li>
              <p>когда необходимо использовать внешние библиотеки</p>
            </li>

            <li>
              <p>для проприетарных, "закрытых" программ
              (скрипты представляют из себя исходные тексты программ,
              доступные для всеобщего обозрения)</p>
            </li>
          </ul>
          <br>
          <br>

          <p>Если выполняется хотя бы одно из вышеперечисленных
          условий, то вам лучше обратиться к более мощным скриптовым
          языкам программирования, например Perl, Tcl, Python, Ruby или
          к высокоуровневым компилирующим языкам -- C, C++ или Java. Но
          даже в этом случае, создание прототипа приложения на языке
          shell может существенно облегчить разработку.</p>

          <p>Название BASH -- это аббревиатура от <span class="QUOTE">"Bourne-Again Shell"</span> и игра
          слов от, ставшего уже классикой, <span class="QUOTE">"Bourne Shell"</span> Стефена Бурна
          (Stephen Bourne). В последние годы BASH достиг такой
          популярности, что стал стандартной командной оболочкой <em class="FOREIGNPHRASE">de facto</em> для многих
          разновидностей UNIX. Большинство принципов программирования
          на BASH одинаково хорошо применимы и в других командных
          оболочках, таких как Korn Shell (ksh), от которой Bash
          позаимствовал некоторые особенности, <a name="AEN165" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN165"><span class="footnote">[2]</span></a> и C Shell и его производных.
          (Примечательно, что C Shell не рекомендуется к использованию
          из-за отдельных проблем, отмеченных Томом Кристиансеном (Tom
          Christiansen) в октябре 1993 года на <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html" "http:="" www.etext.org="" quartz="" computer="" unix="" csh.harmful.gz"="" target="_top">Usenet post</a></p>

          <p>Далее, в тексте документа вы найдете большое количество
          примеров скриптов, иллюстрирующих возможности shell. Все
          примеры -- работающие. Они были протестированы, причем
          некоторые из них могут пригодиться в повседневной работе.
          Уважаемый читатель можеть "поиграть" с рабочим
          кодом скриптов, сохраняя их в файлы, с именами <code class="FILENAME">scriptname.sh</code>. <a name="AEN172" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN172"><span class="footnote">[3]</span></a> Не забудьте выдать этим
          файлам право на исполнение (<code class="USERINPUT"><strong>chmod u+rx
          scriptname</strong></code>), после чего сценарии можно будет
          запустить на исполнение и проверить результат их работы. Вам
          следует помнить, что описание некоторых примеров следует
          после исходного кода этого примера, поэтому, прежде чем
          запустить сценарий у себя -- ознакомьтесь с его
          описанием.</p>

          <p>Скрипты были написаны автором книги, если не оговаривается
          иное.</p>
<blockquote>	<p>Если вы не можете самостоятельно написать скрипт, вы можете найти исполнителя на сайте <!--noindex--><a href="http://www.toptal.com/#hire-just-validated-hackers-today">Toptal</a><!--/noindex-->.</p></blockquote>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="SHA-BANG"></a>Глава 2. Для начала о Sha-Bang</h1>

          <p>В простейшем случае, скрипт -- это ни что иное, как
          простой список команд системы, записанный в файл. Создание
          скриптов поможет сохранить ваше время и силы, которые
          тратятся на ввод последовательности команд всякий раз, когда
          необходимо их выполнить.</p>

          <div class="EXAMPLE">
            <a name="EX1"></a>

            <p><strong>Пример 2-1. cleanup: Сценарий очистки лог-файлов
            в /var/log</strong></p>
<pre class="PROGRAMLISTING cc_cursor"># cleanup
# Для работы сценария требуются права root.

cd /var/log
cat /dev/null &gt; messages
cat /dev/null &gt; wtmp
echo "Лог-файлы очищены."
</pre>
          </div>

          <p>Здесь нет ничего необычного, это простая
          последовательность команд, которая может быть набрана в
          командной строке с консоли или в xterm. Преимущество
          размещения последовательности команд в скрипте состоит в том,
          что вам не придется всякий раз набирать эту
          последовательность вручную. Кроме того, скрипты легко могут
          быть модифицированы или обобщены для разных применений.</p>

          <div class="EXAMPLE">
            <a name="EX2"></a>

            <p><strong>Пример 2-2. cleanup: Расширенная версия
            предыдущего сценария.</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# cleanup, version 2
# Для работы сценария требуются права root.

LOG_DIR=/var/log
ROOT_UID=0     # Только пользователь с $UID 0 имеет привилегии root.
LINES=50       # Количество сохраняемых строк по-умолчанию.
E_XCD=66       # Невозможно сменить каталог?
E_NOTROOT=67   # Признак отсутствия root-привилегий.


if [ "$UID" -ne "$ROOT_UID" ]
then
  echo "Для работы сценария требуются права root."
  exit $E_NOTROOT
fi

if [ -n "$1" ]
# Проверка наличия аргумента командной строки.
then
  lines=$1
else
  lines=$LINES # Значение по-умолчанию, если число не задано в командной строке
fi


#  Stephane Chazelas предложил следующее,
#+ для проверки корректности аргумента, переданного из командной строки,
#+ правда это достаточно сложно для данного руководства.
#
#    E_WRONGARGS=65  # Не числовой аргумент
#
#    case "$1" in
#    ""      ) lines=50;;
#    *[!0-9]*) echo "Usage: `basename $0` file-to-cleanup"; exit $E_WRONGARGS;;
#    *       ) lines=$1;;
#    esac
#
#* Конец проверки корректности аргумента


cd $LOG_DIR

if [ `pwd` != "$LOG_DIR" ]  # или   if [ "$PWD" != "$LOG_DIR" ]
                            # Не в /var/log?
then
  echo "Невозможно перейти в каталог $LOG_DIR."
  exit $E_XCD
fi  # Проверка каталога перед очисткой лог-файлов.

# более эффективный вариант:
#
# cd /var/log || {
#   echo "Невозможно перейти в требуемый каталог." &gt;&amp;2
#   exit $E_XCD;
# }




tail -$lines messages &gt; mesg.temp # Сохранить последние строки в лог-файле.
mv mesg.temp messages


# cat /dev/null &gt; messages
#* Необходимость этой команды отпала, поскольку очистка выполняется выше.

cat /dev/null &gt; wtmp  #  команды ': &gt; wtmp' и '&gt; wtmp'  имеют тот же эффект.
echo "Лог-файлы очищены."

exit 0
#  Возвращаемое значение 0
#+ указывает на успешное завершение работы сценария.
</pre>
          </div>

          <p>Если вы не желаете полностью вычищать системные логи, то
          выше представлена улучшенная версия предыдущего сценария.
          Здесь сохраняются последние несколько строк (по-умолчанию --
          50).</p>

          <p>Если файл сценария начинается с последовательности <span class="TOKEN">#!</span>, которая в мире UNIX называется <em class="FIRSTTERM">sha-bang</em>, то это указывает системе
          какой интерпретатор следует использовать для исполнения
          сценария. <a name="MAGNUMREF"></a>Это двухбайтовая последовательность,
          или <a name="AEN199" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN199"><span class="footnote">[4]</span></a> -- специальный маркер,
          определяющий тип сценария, в данном случае -- сценарий
          командной оболочки (см. <code class="USERINPUT"><strong>man magic</strong></code>). Более
          точно, <span class="emphasis"><em class="EMPHASIS">sha-bang</em></span> определяет
          интерпретатор, который вызывается для исполнения сценария,
          это может быть командная оболочка (shell), иной интерпретатор
          или утилита. <a name="AEN207" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN207"><span class="footnote">[5]</span></a></p>
<pre class="PROGRAMLISTING">#!/bin/sh
#!/bin/bash
#!/usr/bin/perl
#!/usr/bin/tcl
#!/bin/sed -f
#!/usr/awk -f
</pre>
          <br>
          <br>

          <p>Каждая, из приведенных выше сигнатур, приводит к вызову
          различных интерпретаторов, будь то <code class="FILENAME">/bin/sh</code> -- командный интерпретатор
          по-умолчанию (<strong class="COMMAND">bash</strong> для Linux-систем), либо иной.
          <a name="AEN220" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN220"><span class="footnote">[6]</span></a> При <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PORTABILITYISSUES">переносе</a> сценариев с
          сигнатурой <code class="USERINPUT"><strong>#!/bin/sh</strong></code> на другие
          UNIX системы, где в качестве командного интерпретатора задан
          другой shell, вы можете лишиться некоторых особенностей,
          присущих bash. Поэтому такие сценарии должны быть <span class="ACRONYM">POSIX</span> совместимыми. <a name="AEN230" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN230"><span class="footnote">[7]</span></a>.</p>

          <p>Обратите внимание на то, что сигнатура должна указывать
          правильный путь к интерпретатору, в противном случае вы
          получите сообщение об ошибке -- как правило это <span class="QUOTE">"Command not found"</span>.</p>

          <p>Сигнатура <span class="TOKEN">#!</span> может быть опущена, если вы не
          используете специфичных команд. Во втором примере (см. выше)
          использование сигнатуры <span class="TOKEN">#!</span> обязательно, поскольку сценарий
          использует специфичную конструкцию присваивания значения
          переменной <code class="USERINPUT"><strong>lines=50</strong></code>. Еще раз
          замечу, что сигнатура <code class="USERINPUT"><strong>#!/bin/sh</strong></code> вызывает
          командный интерпретатор по-умолчанию -- <code class="FILENAME">/bin/bash</code> в Linux-системах.</p>

          <div class="IMPORTANT">
            <table class="IMPORTANT" width="100%" border="0">
              <tbody><tr>
                <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/important.gif" hspace="5" alt="Important"></td>

                <td align="left" valign="top">
                  <p>В данном руководстве приветствуется модульный
                  подход к построению сценариев. Записывайте, собирайте
                  свою коллекцию участков кода, который может вам
                  встретиться. В конечном итоге вы соберете свою
                  "библиотеку" подпрограмм, которые затем
                  сможете использовать при написании своих сценариев.
                  Например, следующий отрывок сценария проверяет
                  количество аргументов в командной строке:</p>
<pre class="PROGRAMLISTING">if [ $# -ne Number_of_expected_args ]
then
  echo "Usage: `basename $0` whatever"
  exit $WRONG_ARGS
fi
</pre>
                  <br>
                  <br>
                </td>
              </tr>
            </tbody></table>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="INVOKING"></a>2.1. Запуск сценария</h2>

            <p>Запустить сценарий можно командой <code class="USERINPUT"><strong>sh scriptname</strong></code> <a name="AEN253" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN253"><span class="footnote">[8]</span></a> или <code class="USERINPUT"><strong>bash scriptname</strong></code>.
            (Не рекомендуется запуск сценария командой <code class="USERINPUT"><strong>sh
            &lt;scriptname&gt;</strong></code>, поскольку это запрещает
            использование устройства стандартного ввода <code class="FILENAME">stdin</code> в скрипте). Более удобный
            вариант -- сделать файл скрипта исполняемым, командой <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CHMODREF">chmod</a>.</p>

            <div class="VARIABLELIST">
              <dl>
                <dt>Это:</dt>

                <dd>
                  <p><code class="USERINPUT"><strong>chmod 555
                  scriptname</strong></code> (выдача прав на
                  чтение/исполнение любому пользователю в системе) <a name="AEN266" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN266"><span class="footnote">[9]</span></a></p>
                </dd>

                <dt>или</dt>

                <dd>
                  <p><code class="USERINPUT"><strong>chmod +rx
                  scriptname</strong></code> (выдача прав на
                  чтение/исполнение любому пользователю в системе)</p>

                  <p><code class="USERINPUT"><strong>chmod u+rx
                  scriptname</strong></code> (выдача прав на
                  чтение/исполнение только "владельцу"
                  скрипта)</p>
                </dd>
              </dl>
            </div>
            <br>
            <br>

            <p>После того, как вы сделаете файл сценария исполняемым,
            вы можете запустить его примерно такой командой <code class="USERINPUT"><strong>./scriptname</strong></code>. <a name="AEN278" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN278"><span class="footnote">[10]</span></a> Если, при этом, текст
            сценария начинается с корректной сигнатуры (<span class="QUOTE">"sha-bang"</span>), то для его
            исполнения будет вызван соответствующий интерпретатор.</p>

            <p>И наконец, завершив отладку сценария, вы можете
            поместить его в каталог <code class="FILENAME">/usr/local/bin</code> (естественно, что для
            этого вы должны обладать правами root), чтобы сделать его
            доступным для себя и других пользователей системы. После
            этого сценарий можно вызвать, просто напечатав название
            файла в командной строке и нажав клавишу <strong class="KEYCAP">[ENTER]</strong>.</p>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="PRELIMEXER"></a>2.2. Упражнения</h2>

            <ol type="1">
              <li>
                <p>Системные администраторы часто создают скрипты для
                автоматизации своего труда. Подумайте, для выполнения
                каких задач могут быть написаны сценарии.</p>
              </li>

              <li>
                <p>Напишите сценарий, который выводит <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DATEREF">дату, время</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WHOREF">список зарегистрировавшихся
                пользователей</a>, и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#UPTIMEREF">uptime</a> системы и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IOREDIRREF">сохраняет эту информацию</a> в
                системном журнале.</p>
              </li>
            </ol>
          </div>
        </div>
      </div>

      <div class="PART">
        <a name="PART2"></a>

        <div class="TITLEPAGE">
          <h1 class="TITLE">Часть 2. Основы</h1>

          <div class="TOC">
            <dl>
              <dt><strong>Содержание</strong></dt>

              <dt>3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SPECIAL-CHARS">Служебные символы</a></dt>

              <dt>4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#VARIABLES">Переменные и параметры.
              Введение.</a></dt>

              <dd>
                <dl>
                  <dt>4.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#VARSUBN">Подстановка переменных</a></dt>

                  <dt>4.2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#VARASSIGNMENT">Присваивание значений
                  переменным</a></dt>

                  <dt>4.3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#UNTYPED">Переменные Bash не имеют
                  типа</a></dt>

                  <dt>4.4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#OTHERTYPESV">Специальные типы
                  переменных</a></dt>
                </dl>
              </dd>

              <dt>5. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#QUOTING">Кавычки</a></dt>

              <dt>6. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXIT-STATUS">Завершение и код завершения</a></dt>

              <dt>7. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TESTS">Проверка условий</a></dt>

              <dd>
                <dl>
                  <dt>7.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TESTCONSTRUCTS">Конструкции проверки
                  условий</a></dt>

                  <dt>7.2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTO">Операции проверки файлов</a></dt>

                  <dt>7.3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COMPARISON-OPS">Операции сравнения</a></dt>

                  <dt>7.4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#NESTEDIFTHEN">Вложенные условные операторы
                  if/then</a></dt>

                  <dt>7.5. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TESTTEST">Проверка степени усвоения
                  материала</a></dt>
                </dl>
              </dd>

              <dt>8. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#OPERATIONS">Операции и смежные темы</a></dt>

              <dd>
                <dl>
                  <dt>8.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#OPS">Операторы</a></dt>

                  <dt>8.2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#NUMERICAL-CONSTANTS">Числовые
                  константы</a></dt>
                </dl>
              </dd>
            </dl>
          </div>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="SPECIAL-CHARS"></a>Глава 3. Служебные символы</h1>

          <div class="VARIABLELIST">
            <p><strong><a name="SCHARLIST1"></a>Служебные символы, используемые в
            текстах сценариев.</strong></p>

            <dl>
              <dt><span class="TOKEN">#</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>Комментарии.</strong> Строки, начинающиеся
                  с символа <span class="TOKEN">#</span> (<a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MAGNUMREF">за исключением комбинации <span class="TOKEN">#!</span></a>) -- являются
                  комментариями.</p>
                </div>
<pre class="PROGRAMLISTING"># Эта строка -- комментарий.
</pre>
                <br>
                <br>

                <p>Комментарии могут располагаться и в конце строки с
                исполняемым кодом.</p>
<pre class="PROGRAMLISTING">echo "Далее следует комментарий." # Это комментарий.
</pre>
                <br>
                <br>

                <p>Комментариям могут предшествовать <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WHITESPACEREF">пробелы</a> (пробел,
                табуляция).</p>
<pre class="PROGRAMLISTING">       # Перед комментарием стоит символ табуляции.
</pre>
                <br>
                <br>

                <div class="CAUTION">
                  <table class="CAUTION" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                      <td align="left" valign="top">
                        <p>Исполняемые команды не могут следовать за
                        комментарием в той же самой строке. Пока что
                        еще не существует способа отделения комментария
                        от <span class="QUOTE">"исполняемого
                        кода"</span>, следующего за комментарием в
                        той же строке.</p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>

                <div class="NOTE">
                  <table class="NOTE" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                      <td align="left" valign="top">
                        <p>Само собой разумеется, экранированный символ
                        <span class="TOKEN">#</span> в операторе <strong class="COMMAND">echo</strong> не
                        воспринимается как начало комментария. Более
                        того, он может использоваться в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PSUB2">операциях подстановки
                        параметров</a> и в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#NUMCONSTANTS">константных числовых
                        выражениях</a>.</p>
<pre class="PROGRAMLISTING">echo "Символ # не означает начало комментария."
echo 'Символ # не означает начало комментария.'
echo Символ \# не означает начало комментария.
echo А здесь символ # означает начало комментария.

echo ${PATH#*:}       # Подстановка -- не комментарий.
echo $(( 2#101011 ))  # База системы счисления -- не комментарий.

# Спасибо, S.C.
</pre>
                        <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#QUOTINGREF">Кавычки " ' и
                        \</a> экранируют действие символа #. <br>
                        <br>
                      </td>
                    </tr>
                  </tbody></table>
                </div>

                <p>В операциях <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PSOREX1">поиска по шаблону</a> символ <span class="TOKEN">#</span> так же не воспринимается как
                начало комментария.</p>
              </dd>

              <dt><span class="TOKEN">;</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>Разделитель команд.</strong>
                  [Точка-с-запятой] Позволяет записывать две и более
                  команд в одной строке.</p>
                </div>
<pre class="PROGRAMLISTING">echo hello; echo there
</pre>
                <br>
                <br>

                <p>Следует отметить, что символ <span class="QUOTE">"<span class="TOKEN">;</span>"</span> иногда так же как
                и # необходимо <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ESCP">экранировать</a>.</p>
              </dd>

              <dt><span class="TOKEN">;;</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>Ограничитель в операторе выбора <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CASEESAC1">case</a> .</strong>
                  [Двойная-точка-с-запятой]</p>
                </div>
<pre class="PROGRAMLISTING">case "$variable" in
abc)  echo "$variable = abc" ;;
xyz)  echo "$variable = xyz" ;;
esac
</pre>
                <br>
                <br>
              </dd>

              <dt><span class="TOKEN">.</span></dt>

              <dd>
                <p><a name="DOTREF"></a></p>

                <div class="FORMALPARA">
                  <p><strong>команда <span class="QUOTE">"точка"</span>.</strong>
                  Эквивалент команды <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SOURCEREF">source</a> (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX38">Пример 11-18</a>). Это <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BUILTINREF">встроенная</a> команда bash.</p>
                </div>
              </dd>

              <dt><span class="TOKEN">.</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong><span class="QUOTE">"точка"</span> может
                  являться частью имени файла .</strong> Если имя файла
                  начинается с точки, то это <span class="QUOTE">"скрытый"</span> файл, т.е.
                  команда <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LSREF">ls</a> при обычных условиях его не
                  отображает.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>touch .hidden-file</strong></code>
<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>ls -l</strong></code>
<code class="COMPUTEROUTPUT">total 10
 -rw-r--r--    1 bozo      4034 Jul 18 22:04 data1.addressbook
 -rw-r--r--    1 bozo      4602 May 25 13:58 data1.addressbook.bak
 -rw-r--r--    1 bozo       877 Dec 17  2000 employment.addressbook</code>


<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>ls -al</strong></code>
<code class="COMPUTEROUTPUT">total 14
 drwxrwxr-x    2 bozo  bozo      1024 Aug 29 20:54 ./
 drwx------   52 bozo  bozo      3072 Aug 29 20:51 ../
 -rw-r--r--    1 bozo  bozo      4034 Jul 18 22:04 data1.addressbook
 -rw-r--r--    1 bozo  bozo      4602 May 25 13:58 data1.addressbook.bak
 -rw-r--r--    1 bozo  bozo       877 Dec 17  2000 employment.addressbook
 -rw-rw-r--    1 bozo  bozo         0 Aug 29 20:54 .hidden-file</code>
               
</pre>
                  <br>
                  <br>
                </div>

                <p>Если подразумевается имя каталога, то <span class="emphasis"><em class="EMPHASIS">одна точка</em></span> означает
                текущий каталог и <span class="emphasis"><em class="EMPHASIS">две точки</em></span> -- каталог
                уровнем выше, или родительский каталог.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>pwd</strong></code>
<code class="COMPUTEROUTPUT">/home/bozo/projects</code>

<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>cd .</strong></code>
<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>pwd</strong></code>
<code class="COMPUTEROUTPUT">/home/bozo/projects</code>

<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>cd ..</strong></code>
<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>pwd</strong></code>
<code class="COMPUTEROUTPUT">/home/bozo/</code>
               
</pre>
                <br>
                <br>

                <p>Символ <span class="emphasis"><em class="EMPHASIS">точка</em></span> довольно часто
                используется для обозначения каталога назначения в
                операциях копирования/перемещения файлов.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>cp /home/bozo/current_work/junk/* .</strong></code>
               
</pre>
                <br>
                <br>
              </dd>

              <dt><span class="TOKEN">.</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>Символ <span class="QUOTE">"точка"</span> в операциях
                  поиска.</strong> При выполнении <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REGEXDOT">поиска по шаблону</a> , в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REGEXREF">регулярных выражениях</a>, символ
                  <span class="QUOTE">"точка"</span> обозначает
                  одиночный символ.</p>
                </div>
              </dd>

              <dt><span class="TOKEN">"</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DBLQUO">Двойные кавычки</a> .</strong> В
                  строке <span class="emphasis"><em class="EMPHASIS">"STRING"</em></span>,
                  ограниченной двойными кавычками не выполняется
                  интерпретация большинства служебных символов, которые
                  могут находиться в строке. см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#QUOTING">Глава 5</a>.</p>
                </div>
              </dd>

              <dt><span class="TOKEN">'</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SNGLQUO">Одинарные кавычки</a> .</strong>
                  [Одинарные кавычки] <span class="emphasis"><em class="EMPHASIS">'STRING'</em></span>
                  экранирует все служебные символы в строке <span class="emphasis"><em class="EMPHASIS">STRING</em></span>. Это более
                  строгая форма экранирования. Смотрите так же <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#QUOTING">Глава 5</a>.</p>
                </div>
              </dd>

              <dt><span class="TOKEN">,</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COMMAOP">Запятая</a> .</strong> Оператор
                  <strong class="COMMAND">запятая</strong> используется для
                  вычисления серии арифметических выражений.
                  Вычисляются все выражения, но возвращается результат
                  последнего выражения.</p>
<pre class="PROGRAMLISTING">let "t2 = ((a = 9, 15 / 3))"  # Присваивает значение переменной "a" и вычисляет "t2".
</pre>
                  <br>
                  <br>
                </div>
              </dd>

              <dt><span class="TOKEN">\</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ESCP">escape</a>.</strong> [обратный слэш]
                  Комбинация <code class="USERINPUT"><strong>\X</strong></code> <span class="QUOTE">"экранирует"</span> символ
                  <span class="emphasis"><em class="EMPHASIS">X</em></span>. Аналогичный эффект
                  имеет комбинация с <span class="QUOTE">"одинарными
                  кавычками"</span>, т.е. <span class="emphasis"><em class="EMPHASIS">'X'</em></span>. Символ
                  <span class="TOKEN">\</span> может использоваться для
                  экранирования кавычек <span class="TOKEN">"</span> и <span class="TOKEN">'</span>.</p>
                </div>

                <p>Более детальному рассмотрению темы экранирования
                посвящена <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#QUOTING">Глава 5</a>.</p>
              </dd>

              <dt><span class="TOKEN">/</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>Разделитель, используемый в указании пути
                  к каталогам и файлам.</strong> [слэш] Отделяет
                  элементы пути к каталогам и файлам (например <code class="FILENAME">/home/bozo/projects/Makefile</code>).</p>
                </div>

                <p>В <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AROPS1">арифметических операциях</a> -- это
                оператор деления.</p>
              </dd>

              <dt><span class="TOKEN">`</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COMMANDSUBREF">Подстановка
                  команд</a>.</strong> [обратные кавычки] <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BACKQUOTESREF">Обратные кавычки</a> могут
                  использоваться для записи в переменную команды <span class="emphasis"><em class="EMPHASIS">`command`</em></span>.</p>
                </div>
              </dd>

              <dt><span class="TOKEN">:</span></dt>

              <dd>
                <p><a name="NULLREF"></a></p>

                <div class="FORMALPARA">
                  <p><strong>пустая команда.</strong> [двоеточие] Это
                  эквивалент операции <span class="QUOTE">"NOP"</span> (<code class="REPLACEABLE"><em>no op</em></code>, нет
                  операции). Может рассматриваться как синоним
                  встроенной команды <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TRUEREF">true</a>. Команда <span class="QUOTE">"<span class="TOKEN">:</span>"</span> так же является
                  встроенной командой Bash, которая всегда <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXITSTATUSREF">возвращает</a> <span class="QUOTE">"true"</span> (<span class="RETURNVALUE">0</span>).</p>
                </div>
<pre class="PROGRAMLISTING">:
echo $?   # 0
</pre>
                <br>
                <br>

                <p>Бесконечный цикл:</p>
<pre class="PROGRAMLISTING">while :
do
   operation-1
   operation-2
   ...
   operation-n
done

# То же самое:
#    while true
#    do
#      ...
#    done
</pre>
                <br>
                <br>

                <p>Символ-заполнитель в условном операторе if/then:</p>
<pre class="PROGRAMLISTING">if condition
then :   # Никаких действий не производится и управление передается дальше
else
   take-some-action
fi
</pre>
                <br>
                <br>

                <p>Как символ-заполнитель в операциях, которые
                предполагают наличие двух операндов, см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ARITHOPS">Пример 8-2</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DEFPARAM">параметры по-умолчанию</a>.</p>
<pre class="PROGRAMLISTING">: ${username=`whoami`}
# ${username=`whoami`}   без символа : выдает сообщение об ошибке,
#                        если "username" не является командой...
</pre>
                <br>
                <br>

                <p>Как символ-заполнитель для оператора <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#HEREDOCREF">вложенного документа</a>. См. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ANONHEREDOC">Пример 17-9</a>.</p>

                <p>В операциях с <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PARAMSUBREF">подстановкой параметров</a> (см.
                <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX6">Пример 9-13</a>).</p>
<pre class="PROGRAMLISTING">: ${HOSTNAME?} ${USER?} ${MAIL?}
#Вывод сообщения об ошибке, если одна или более переменных не определены.
</pre>
                <br>
                <br>

                <p>В операциях <strong class="COMMAND"><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXPREPL1">замены подстроки с подстановкой
                значений переменных</a></strong>.</p>

                <p>В комбинации с оператором <span class="TOKEN">&gt;</span> (<a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IOREDIRREF">оператор перенаправления
                вывода</a>), усекает длину файла до нуля. Если указан
                несуществующий файл -- то он создается.</p>
<pre class="PROGRAMLISTING">: &gt; data.xxx   # Файл "data.xxx" -- пуст

# Тот же эффект имеет команда cat /dev/null &gt;data.xxx
# Однако в данном случае не производится создание нового процесса, поскольку ":" является встроенной командой.
</pre>
                См. так же <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX12">Пример 12-11</a>.<br>
                <br>

                <p>В комбинации с оператором <span class="TOKEN">&gt;&gt;</span> -- оператор
                перенаправления с добавлением в конец файла и
                обновлением времени последнего доступа (<code class="USERINPUT"><strong>: &gt;&gt;
                new_file</strong></code>). Если задано имя
                несуществующего файла, то он создается. Эквивалентно
                команде <code>touch</code>.</p>

                <div class="NOTE">
                  <table class="NOTE" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                      <td align="left" valign="top">
                        <p>Вышеизложенное применимо только к обычным
                        файлам и неприменимо к конвейерам,
                        символическим ссылкам и другим специальным
                        файлам.</p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>

                <p>Символ <span class="TOKEN">:</span> может использоваться для
                создания комментариев, хотя и не рекомендуется. Если
                строка комментария начинается с символа <span class="TOKEN">#</span>, то такая строка не проверяется
                интерпретатором на наличие ошибок. Однако в случае
                оператора <span class="TOKEN">:</span> это не так.</p>
<pre class="PROGRAMLISTING">: Это комментарий, который генерирует сообщение об ошибке, ( if [ $x -eq 3] ).
</pre>
                <br>
                <br>

                <p>Символ <span class="QUOTE">"<span class="TOKEN">:</span>"</span> может
                использоваться как разделитель полей в <code class="FILENAME">/etc/passwd</code> и переменной <code>$PATH</code>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo $PATH</strong></code>
<code class="COMPUTEROUTPUT">/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/sbin:/usr/sbin:/usr/games</code>
</pre>
                <br>
                <br>
              </dd>

              <dt><span class="TOKEN">!</span></dt>

              <dd>
                <p><a name="NOTREF"></a></p>

                <div class="FORMALPARA">
                  <p><strong>инверсия (или логическое отрицание)
                  используемое в условных операторах.</strong> Оператор
                  <span class="TOKEN">!</span> инвертирует <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXITSTATUSREF">код завершения</a> команды, к
                  которой он применен. (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#NEGCOND">Пример 6-2</a>). Так же используется
                  для логического отрицания в операциях сравнения,
                  например, операция сравнения <span class="QUOTE">"равно"</span> ( <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EQUALSIGNREF">=</a> ), при использовании
                  оператора отрицания, преобразуется в операцию
                  сравнения -- <span class="QUOTE">"не равно"</span> ( != ).
                  Символ <span class="TOKEN">!</span> является зарезервированным
                  ключевым словом BASH.</p>
                </div>

                <p>В некоторых случаях символ <span class="TOKEN">!</span> используется для <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IVR2">косвенного обращения к
                переменным</a>.</p>

                <p>Кроме того, из <span class="emphasis"><em class="EMPHASIS">командной строки</em></span> оператор
                <span class="TOKEN">!</span> запускает <span class="emphasis"><em class="EMPHASIS">механизм историй</em></span> Bash
                (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#HISTCOMMANDS">Приложение F</a>). Примечательно,
                что этот механизм недоступен из сценариев (т.е.
                исключительно из командной строки).</p>
              </dd>

              <dt><span class="TOKEN">*</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>символ-шаблон.</strong> [звездочка] Символ
                  <span class="TOKEN">*</span> служит <span class="QUOTE">"шаблоном"</span> для <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GLOBBINGREF">подстановки</a> в имена файлов.
                  Одиночный символ <span class="TOKEN">*</span> означает любое имя файла в
                  заданном каталоге.</p>
                </div>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo *</strong></code>
<code class="COMPUTEROUTPUT">abs-book.sgml add-drive.sh agram.sh alias.sh</code>
             
</pre>
                <br>
                <br>

                <p>В <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REGEXREF">регулярных выражениях</a> токен <span class="TOKEN">*</span> представляет любое количество
                (в том числе и 0) символов.</p>
              </dd>

              <dt><span class="TOKEN">*</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AROPS1">арифметический оператор</a>.</strong>
                  В арифметических выражениях символ <span class="TOKEN">*</span> обозначает операцию
                  умножения.</p>
                </div>

                <p>Двойная звездочка (два символа звездочки, следующих
                подряд друг за другом -- <span class="TOKEN">**</span>), обозначает операцию <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXPONENTIATIONREF">возведения в
                степень</a>.</p>
              </dd>

              <dt><span class="TOKEN">?</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>Оператор проверки условия.</strong> В
                  некоторых выражениях символ <span class="TOKEN">?</span> служит для проверки
                  выполнения условия.</p>
                </div>

                <p>В <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DBLPARENS">конструкциях с двойными
                скобками</a>, символ <span class="TOKEN">?</span> подобен трехместному оператору
                языка C. См. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CVARS">Пример 9-28</a>.</p>

                <p>В выражениях с <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PARAMSUBREF">подстановкой параметра</a>, символ
                <span class="TOKEN">?</span> <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#QERRMSG">проверяет -- установлена ли
                переменная</a>.</p>
              </dd>

              <dt><span class="TOKEN">?</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>символ-шаблон.</strong> Символ <span class="TOKEN">?</span> обозначает одиночный символ
                  при <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GLOBBINGREF">подстановке</a> в имена файлов.
                  В <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXTREGEX">регулярных выражениях</a> служит
                  для обозначения <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#QUEXREGEX">одиночного символа</a>.</p>
                </div>
              </dd>

              <dt><span class="TOKEN">$</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#VARSUBN">Подстановка
                  переменной</a>.</strong></p>
<pre class="PROGRAMLISTING">var1=5
var2=23skidoo

echo $var1     # 5
echo $var2     # 23skidoo
</pre>
                  <br>
                  <br>
                </div>

                <p>Символ <span class="TOKEN">$</span>, предшествующий имени
                переменной, указывает на то, что будет получено <span class="emphasis"><em class="EMPHASIS">значение</em></span> переменной.</p>
              </dd>

              <dt><span class="TOKEN">$</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>end-of-line (конец строки).</strong> В <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REGEXREF">регулярных выражениях</a>, символ
                  <span class="QUOTE">"$"</span> обозначает конец
                  строки.</p>
                </div>
              </dd>

              <dt><span class="TOKEN">${}</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PARAMSUBREF">Подстановка
                  параметра</a>.</strong></p>
                </div>
              </dd>

              <dt><span class="TOKEN">$*</span>, <span class="TOKEN">$@</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#APPREF">параметры командной
                  строки</a>.</strong></p>
                </div>
              </dd>

              <dt><span class="TOKEN">$?</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>код завершения.</strong> <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXSREF">Переменная $?</a> хранит <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXITSTATUSREF">код завершения</a> последней
                  выполненной команды, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FUNCTIONREF">функции</a> или сценария.</p>
                </div>
              </dd>

              <dt><span class="TOKEN">$$</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>id процесса.</strong> <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PROCCID">Переменная $$</a> хранит <span class="emphasis"><em class="EMPHASIS">id процесса</em></span>
                  сценария.</p>
                </div>
              </dd>

              <dt><span class="TOKEN">()</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>группа команд.</strong></p>
<pre class="PROGRAMLISTING">(a=hello; echo $a)
</pre>
                  <br>
                  <br>
                </div>

                <div class="IMPORTANT">
                  <table class="IMPORTANT" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/important.gif" hspace="5" alt="Important"></td>

                      <td align="left" valign="top">
                        <p>Команды, заключенные в <code class="REPLACEABLE"><em>круглые
                        скобки</em></code> исполняются в дочернем
                        процессе -- <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SUBSHELLSREF">subshell-е</a>.</p>

                        <p>Переменные, создаваемые в дочернем процессе
                        не видны в "родительском" сценарии.
                        Родительский процесс-сценарий, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PARVIS">не может обращаться к
                        переменным, создаваемым в дочернем
                        процессе</a>.</p>
<pre class="PROGRAMLISTING">a=123
( a=321; )

echo "a = $a"   # a = 123
# переменная "a" в скобках подобна локальной переменной.
</pre>
                        <br>
                        <br>
                      </td>
                    </tr>
                  </tbody></table>
                </div>

                <div class="FORMALPARA">
                  <p><strong>инициализация массивов.</strong></p>
<pre class="PROGRAMLISTING">Array=(element1 element2 element3)
</pre>
                  <br>
                  <br>
                </div>
              </dd>

              <dt><span class="TOKEN">{xxx,yyy,zzz,...}</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>Фигурные скобки.</strong></p>
<pre class="PROGRAMLISTING">grep Linux file*.{txt,htm*}
# Поиск всех вхождений слова "Linux"
# в файлах "fileA.txt", "file2.txt", "fileR.html", "file-87.htm", и пр.
</pre>
                  <br>
                  <br>
                </div>

                <p>Команда интерпретируется как список команд,
                разделенных точкой с запятой, с вариациями,
                представленными в <code class="REPLACEABLE"><em>фигурных скобках</em></code>. <a name="AEN901" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN901"><span class="footnote">[11]</span></a> При интерпретации
                имен файлов (<a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GLOBBINGREF">подстановка</a>) используются
                параметры, заключенные в фигурные скобки.</p>

                <div class="CAUTION">
                  <table class="CAUTION" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                      <td align="left" valign="top">
                        <p>Использование <span class="emphasis"><em class="EMPHASIS">неэкранированных или
                        неокавыченных</em></span> пробелов внутри
                        фигурных скобок недопустимо.</p>

                        <p><code class="USERINPUT"><strong>echo {file1,file2}\
                        :{\ A," B",'
                        C'}</strong></code></p>

                        <p><code class="COMPUTEROUTPUT">file1 : A file1 : B
                        file1 : C file2 : A file2 : B file2 :
                        C</code></p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </dd>

              <dt><span class="TOKEN">{}</span></dt>

              <dd>
                <p><a name="CODEBLOCKREF"></a></p>

                <div class="FORMALPARA">
                  <p><strong>Блок кода.</strong> [фигурные скобки]
                  Известен так же как <span class="QUOTE">"вложенный блок"</span>, эта
                  конструкция, фактически, создает анонимную функцию.
                  Однако, в отличии от обычных <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FUNCTIONREF">функций</a>, переменные,
                  создаваемые во вложенных блоках кода, доступны
                  объемлющему сценарию.</p>
                </div>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>{ local a; a=123; }</strong></code>
<code class="COMPUTEROUTPUT">bash: local: can only be used in a function</code>
             
</pre>
                <br>
                <br>
<pre class="PROGRAMLISTING">a=123
{ a=321; }
echo "a = $a"   # a = 321   (значение, присвоенное во вложенном блоке кода)

# Спасибо, S.C.
</pre>
                <br>
                <br>

                <p>Код, заключенный в фигурные скобки, может выполнять
                <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IOREDIRREF">перенаправление
                ввода-вывода</a>.</p>

                <div class="EXAMPLE">
                  <a name="EX8"></a>

                  <p><strong>Пример 3-1. Вложенные блоки и
                  перенаправление ввода-вывода</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Чтение строк из файла /etc/fstab.

File=/etc/fstab

{
read line1
read line2
} &lt; $File

echo "Первая строка в $File :"
echo "$line1"
echo
echo "Вторая строка в $File :"
echo "$line2"

exit 0
</pre>
                </div>

                <div class="EXAMPLE">
                  <a name="RPMCHECK"></a>

                  <p><strong>Пример 3-2. Сохранение результата
                  исполнения вложенного блока в файл</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# rpm-check.sh

# Запрашивает описание rpm-архива, список файлов, и проверяется возможность установки.
# Результат сохраняется в файле.
#
# Этот сценарий иллюстрирует порядок работы со вложенными блоками кода.

SUCCESS=0
E_NOARGS=65

if [ -z "$1" ]
then
  echo "Порядок использования: `basename $0` rpm-file"
  exit $E_NOARGS
fi

{
  echo
  echo "Описание архива:"
  rpm -qpi $1       # Запрос описания.
  echo
  echo "Список файлов:"
  rpm -qpl $1       # Запрос списка.
  echo
  rpm -i --test $1  # Проверка возможности установки.
  if [ "$?" -eq $SUCCESS ]
  then
    echo "$1 может быть установлен."
  else
    echo "$1 -- установка невозможна!"
  fi
  echo
} &gt; "$1.test"       # Перенаправление вывода в файл.

echo "Результаты проверки rpm-архива находятся в файле $1.test"

# За дополнительной информацией по ключам команды rpm см. man rpm.

exit 0
</pre>
                </div>

                <div class="NOTE">
                  <table class="NOTE" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                      <td align="left" valign="top">
                        <p>В отличие от групп команд в (круглых
                        скобках), описаных выше, вложенные блоки кода,
                        заключенные в {фигурные скобки} исполняются в
                        пределах того же процесса, что и сам скрипт
                        (т.е. не вызывают запуск дочернего процесса --
                        <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SUBSHELLSREF">subshell</a>). <a name="AEN947" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN947"><span class="footnote">[12]</span></a></p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </dd>

              <dt><span class="TOKEN">{} \;</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>pathname -- полное имя файла (т.е. путь к
                  файлу и его имя).</strong> Чаще всего используется
                  совместно с командой <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FINDREF">find</a>.</p>
                </div>

                <div class="NOTE">
                  <table class="NOTE" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                      <td align="left" valign="top">
                        <p>Обратите внимание на то, что символ <span class="QUOTE">"<span class="TOKEN">;</span>"</span>, которым
                        завершается ключ <code class="OPTION">-exec</code> команды <strong class="COMMAND">find</strong>, экранируется
                        обратным слэшем. Это необходимо, чтобы
                        предотвратить его интерпретацию.</p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </dd>

              <dt><span class="TOKEN">[ ]</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>test.</strong></p>
                </div>

                <p><a name="LEFTBRACKET"></a><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IFTHEN">Проверка истинности</a> выражения,
                заключенного в квадратные скобки <strong class="COMMAND">[ ]</strong>. Примечательно, что
                <strong class="COMMAND">[</strong> является частью встроенной
                команды <strong class="COMMAND">test</strong> (и ее синонимом), И
                <span class="emphasis"><em class="EMPHASIS">не</em></span> имеет никакого
                отношения к "внешней" утилите <code class="FILENAME">/usr/bin/test</code>.</p>
              </dd>

              <dt><span class="TOKEN">[[ ]]</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>test.</strong></p>
                </div>

                <p>Проверка истинности выражения, заключенного между
                <span class="TOKEN">[[ ]]</span> (<a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#KEYWORDREF">зарезервированное слово</a>
                интерпретатора).</p>

                <p>См. описание конструкции <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DBLBRACKETS">[[ ... ]]</a> ниже.</p>
              </dd>

              <dt><span class="TOKEN">[ ]</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>элемент массива.</strong></p>
                </div>

                <p>При работе с <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ARRAYREF">массивами</a> в квадратных скобках
                указывается порядковый номер того элемента массива, к
                которому производится обращение.</p>
<pre class="PROGRAMLISTING">Array[1]=slot_1
echo ${Array[1]}
</pre>
                <br>
                <br>
              </dd>

              <dt><span class="TOKEN">[ ]</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>диапазон символов.</strong></p>
                </div>

                <p>В <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REGEXREF">регулярных выражениях</a>, в
                квадратных скобках задается <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BRACKETSREF">диапазон искомых символов</a>.</p>
              </dd>

              <dt><span class="TOKEN">(( ))</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>двойные круглые скобки.</strong></p>
                </div>

                <p>Вычисляется целочисленное выражение, заключенное
                между двойными круглыми скобками <span class="TOKEN">(( ))</span>.</p>

                <p>См. обсуждение, посвященное <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DBLPARENS">конструкции (( ... ))</a> .</p>
              </dd>

              <dt><span class="TOKEN">&gt;</span> <span class="TOKEN">&amp;&gt;</span> <span class="TOKEN">&gt;&amp;</span> <span class="TOKEN">&gt;&gt;</span> <span class="TOKEN">&lt;</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IOREDIRREF">перенаправление</a>.</strong></p>
                </div>

                <p>Конструкция <code class="USERINPUT"><strong>scriptname
                &gt;filename</strong></code> перенаправляет вывод <code class="FILENAME">scriptname</code> в файл <code class="FILENAME">filename</code>. Если файл <code class="FILENAME">filename</code> уже существовал, то его
                прежнее содержимое будет утеряно.</p>

                <p>Конструкция <code class="USERINPUT"><strong>command
                &amp;&gt;filename</strong></code> перенаправляет вывод
                команды <code class="FILENAME">command</code>, как со <code class="FILENAME">stdout</code>, так и с <code class="FILENAME">stderr</code>, в файл <code class="FILENAME">filename</code>.</p>

                <p>Конструкция <code class="USERINPUT"><strong>command
                &gt;&amp;2</strong></code> перенаправляет вывод со <code class="FILENAME">stdout</code> на <code class="FILENAME">stderr</code>.</p>

                <p>Конструкция <code class="USERINPUT"><strong>scriptname
                &gt;&gt;filename</strong></code> добавляет вывод <code class="FILENAME">scriptname</code> к файлу <code class="FILENAME">filename</code>. Если задано имя
                несуществующего файла, то он создается.</p>

                <div class="FORMALPARA">
                  <p><strong><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PROCESSSUBREF">подстановка
                  процесса</a>.</strong></p>
                </div>

                <p><code class="USERINPUT"><strong>(command)&gt;</strong></code></p>

                <p><code class="USERINPUT"><strong>&lt;(command)</strong></code></p>

                <p>В <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LTREF">операциях сравнения</a>, символы <span class="QUOTE">"<span class="TOKEN">&lt;</span>"</span> и <span class="QUOTE">"<span class="TOKEN">&gt;</span>"</span> обозначают
                операции <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SCOMPARISON1">сравнения строк</a> .</p>

                <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#INTLT">А так же</a> -- операции <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ICOMPARISON1">сравнения целых чисел</a>. См.
                так же <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX45">Пример 12-6</a>.</p>
              </dd>

              <dt><span class="TOKEN">&lt;&lt;</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>перенаправление ввода на <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#HEREDOCREF">встроенный
                  документ</a>.</strong></p>
                </div>
              </dd>

              <dt><span class="TOKEN">&lt;</span>, <span class="TOKEN">&gt;</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LTREF">Посимвольное
                  ASCII-сравнение</a>.</strong></p>
<pre class="PROGRAMLISTING">veg1=carrots
veg2=tomatoes

if [[ "$veg1" &lt; "$veg2" ]]
then
  echo "Не смотря на то, что в словаре слово $veg1 предшествует слову $veg2,"
  echo "это никак не отражает мои кулинарные предпочтения."
else
  echo "Интересно. Каким словарем вы пользуетесь?"
fi
</pre>
                  <br>
                  <br>
                </div>
              </dd>

              <dt><span class="TOKEN">\&lt;</span>, <span class="TOKEN">\&gt;</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ANGLEBRAC">границы отдельных слов</a> в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REGEXREF">регулярных
                  выражениях</a>.</strong></p>
                </div>

                <p><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>grep '\&lt;the\&gt;'
                textfile</strong></code></p>
              </dd>

              <dt><span class="TOKEN">|</span></dt>

              <dd>
                <p><a name="PIPEREF"></a></p>

                <div class="FORMALPARA">
                  <p><strong>конвейер.</strong> Передает вывод
                  предыдущей команды на ввод следующей или на вход
                  командного интерпретатора shell. Этот метод часто
                  используется для связывания последовательности команд
                  в единую цепочку.</p>
                </div>
<pre class="PROGRAMLISTING">echo ls -l | sh
#  Передает вывод "echo ls -l" команлному интерпретатору shell,
#+ тот же результат дает простая команда "ls -l".


cat *.lst | sort | uniq
# Объединяет все файлы ".lst", сортирует содержимое и удаляет повторяющиеся строки.
</pre>
                <br>
                <br>

                <table class="SIDEBAR" border="1" cellpadding="5">
                  <tbody><tr>
                    <td>
                      <div class="SIDEBAR">
                        <a name="AEN1202"></a>

                        <p>Конвейеры (еще их называют каналами) -- это
                        классический способ взаимодействия процессов, с
                        помощью которого <code class="FILENAME">stdout</code> одного процесса
                        перенаправляется на <code class="FILENAME">stdin</code> другого. Обычно
                        используется совместно с командами вывода,
                        такими как <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CATREF">cat</a> или <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ECHOREF">echo</a>, от которых поток
                        данных поступает в <span class="QUOTE">"фильтр"</span>
                        (команда, которая на входе получает данные,
                        преобразует их и обрабатывает).</p>

                        <p><code class="USERINPUT"><strong>cat $filename | grep
                        $search_word</strong></code></p>
                      </div>
                    </td>
                  </tr>
                </tbody></table>

                <p><a name="UCREF"></a>В конвейер могут объединяться и
                сценарии на языке командной оболочки.</p>
<pre class="PROGRAMLISTING">#!/bin/bash
# uppercase.sh : Преобразование вводимых символов в верхний регистр.

tr 'a-z' 'A-Z'
#  Диапазоны символов должны быть заключены в кавычки
#+ чтобы предотвратить порождение имен файлов от однобуквенных имен файлов.

exit 0
</pre>
                А теперь попробуем объединить в конвейер команду
                <strong class="COMMAND">ls -l</strong> с этим сценарием. 
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>ls -l | ./uppercase.sh</strong></code>
<code class="COMPUTEROUTPUT">-RW-RW-R--    1 BOZO  BOZO       109 APR  7 19:49 1.TXT
 -RW-RW-R--    1 BOZO  BOZO       109 APR 14 16:48 2.TXT
 -RW-R--R--    1 BOZO  BOZO       725 APR 20 20:56 DATA-FILE</code>
             
</pre>
                <br>
                <br>

                <div class="NOTE">
                  <table class="NOTE" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                      <td align="left" valign="top">
                        <p>Выход <code class="FILENAME">stdout</code> каждого процесса
                        в конвейере должен читаться на входе <code class="FILENAME">stdin</code> последующим, в
                        конвейере, процессом. Если этого не делается,
                        то поток данных <span class="emphasis"><em class="EMPHASIS">блокируется</em></span>, в
                        результате конвейер будет работать не так как
                        ожидается.</p>
<pre class="PROGRAMLISTING">cat file1 file2 | ls -l | sort
# Вывод команды "cat file1 file2" будет утерян.
</pre>
                        <br>
                        <br>

                        <p>Конвейер исполняется в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CHILDREF">дочернем процессе</a>, а
                        посему -- не имеет доступа к переменным
                        сценария.</p>
<pre class="PROGRAMLISTING">variable="initial_value"
echo "new_value" | read variable
echo "variable = $variable"     # variable = initial_value
</pre>
                        <br>
                        <br>

                        <p>Если одна из команд в конвейере завершается
                        аварийно, то это приводит к аварийному
                        завершению работы всего конвейера.</p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </dd>

              <dt><span class="TOKEN">&gt;|</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>принудительное перенаправление, даже если
                  установлен ключ <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#NOCLOBBERREF">noclobber
                  option</a>.</strong></p>
                </div>
              </dd>

              <dt><span class="TOKEN">||</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ORREF">логическая операция OR (логическое
                  ИЛИ)</a>.</strong> В <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TESTCONSTRUCTS1">опрециях проверки
                  условий</a>, оператор <span class="TOKEN">||</span> возвращает <span class="RETURNVALUE">0</span> (success), если один из
                  операндов имеет значение true (ИСТИНА).</p>
                </div>
              </dd>

              <dt><span class="TOKEN">&amp;</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>Выполнение задачи в фоне.</strong>
                  Команда, за которой стоит <span class="TOKEN">&amp;</span>, будет исполняться в
                  фоновом режиме.</p>
                </div>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>sleep 10 &amp;</strong></code>
<code class="COMPUTEROUTPUT">[1] 850</code>
<code class="COMPUTEROUTPUT">[1]+  Done                    sleep 10</code>
             
</pre>
                <br>
                <br>

                <p>В сценариях команды, и даже <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FORLOOPREF1">циклы</a> могут запускаться в
                фоновом режиме.</p>

                <div class="EXAMPLE">
                  <a name="BGLOOP"></a>

                  <p><strong>Пример 3-3. Запуск цикла в фоновом
                  режиме</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# background-loop.sh

for i in 1 2 3 4 5 6 7 8 9 10            # Первый цикл.
do
  echo -n "$i "
done &amp; # Запуск цикла в фоне.
       # Иногда возможны случаи выполнения этого цикла после второго цикла.

echo   # Этот 'echo' иногда не отображается на экране.

for i in 11 12 13 14 15 16 17 18 19 20   # Второй цикл.
do
  echo -n "$i "
done

echo   # Этот 'echo' иногда не отображается на экране.

# ======================================================

# Ожидается, что данный сценарий выведет следующую последовательность:
# 1 2 3 4 5 6 7 8 9 10
# 11 12 13 14 15 16 17 18 19 20

# Иногда возможен такой вариант:
# 11 12 13 14 15 16 17 18 19 20
# 1 2 3 4 5 6 7 8 9 10 bozo $
# (Второй 'echo' не был выполнен. Почему?)

# Изредка возможен такой вариант:
# 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
# (Первый 'echo' не был выполнен. Почему?)

# Крайне редко встречается и такое:
# 11 12 13 1 2 3 4 5 6 7 8 9 10 14 15 16 17 18 19 20
# Второй цикл начал исполняться раньше первого.

exit 0
</pre>
                </div>

                <div class="CAUTION">
                  <table class="CAUTION" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                      <td align="left" valign="top">
                        <p>Команда, исполняемая в пределах сценария в
                        фоне, может подвесить сценарий, ожидая нажатия
                        клавиши. К счастью, это легко <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WAITHANG">"лечится"</a>.</p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </dd>

              <dt><span class="TOKEN">&amp;&amp;</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LOGOPS1">Логическая операция AND (логическое
                  И)</a>.</strong> В <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TESTCONSTRUCTS1">операциях проверки
                  условий</a>, оператор <span class="TOKEN">&amp;&amp;</span> возвращает <span class="RETURNVALUE">0</span> (success) тогда, и
                  только тогда, когда <span class="emphasis"><em class="EMPHASIS">оба</em></span> операнда имеют
                  значение true (ИСТИНА).</p>
                </div>
              </dd>

              <dt><a name="DAS"></a><span class="TOKEN">-</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>префикс ключа.</strong> С этого символа
                  начинаются опциональные ключи команд.</p>
                </div>

                <p><code class="USERINPUT"><strong>COMMAND
                -[Option1][Option2][...]</strong></code></p>

                <p><code class="USERINPUT"><strong>ls -al</strong></code></p>

                <p><code class="USERINPUT"><strong>sort -dfu
                $filename</strong></code></p>

                <p><code class="USERINPUT"><strong>set --
                $variable</strong></code></p>
<pre class="PROGRAMLISTING">if [ $file1 -ot $file2 ]
then
  echo "Файл $file1 был создан раньше чем $file2."
fi

if [ "$a" -eq "$b" ]
then
  echo "$a равно $b."
fi

if [ "$c" -eq 24 -a "$d" -eq 47 ]
then
  echo "$c равно 24, а $d равно 47."
fi
</pre>
                <br>
                <br>
              </dd>

              <dt><span class="TOKEN">-</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>перенаправление из/в <code class="FILENAME">stdin</code> или <code class="FILENAME">stdout</code>.</strong> <a name="COXEX"></a>[дефис]</p>
                </div>
<pre class="PROGRAMLISTING">(cd /source/directory &amp;&amp; tar cf - . ) | (cd /dest/directory &amp;&amp; tar xpvf -)
# Перемещение полного дерева файлов и подкаталогов из одной директории в другую
# [спасибо Алану Коксу (Alan Cox) &lt;a.cox@swansea.ac.uk&gt;, за небольшие поправки]

# 1) cd /source/directory    Переход в исходный каталог, содержимое которого будет перемещено
# 2) &amp;&amp;                     "И-список": благодаря этому все последующие команды будут выполнены
#                            только тогда, когда 'cd' завершится успешно
# 3) tar cf - .              ключом 'c' архиватор 'tar' создает новый архив,
#                            ключом 'f' (file) и последующим '-' задается файл архива -- stdout,
#                            в архив помещается текущий каталог ('.') с вложенными подкаталогами.
# 4) |                       конвейер с ...
# 5) ( ... )                 subshell-ом (дочерним экземпляром командной оболочки)
# 6) cd /dest/directory      Переход в каталог назначения.
# 7) &amp;&amp;                     "И-список", см. выше
# 8) tar xpvf -              Разархивирование ('x'), с сохранением атрибутов "владельца" и прав доступа ('p') к файлам,
#                            с выдачей более подробных сообщений на stdout ('v'),
#                            файл архива -- stdin ('f' с последующим '-').
#
#                            Примечательно, что 'x' -- это команда, а 'p', 'v' и 'f' -- ключи
# Во как!



# Более элегантный вариант:
#   cd source-directory
#   tar cf - . | (cd ../target-directory; tar xzf -)
#
# cp -a /source/directory /dest     имеет тот же эффект.
</pre>
                <br>
                <br>
<pre class="PROGRAMLISTING">bunzip2 linux-2.4.3.tar.bz2 | tar xvf -
# --разархивирование tar-файла--    | --затем файл передается утилите "tar"--
# Если у вас утилита "tar" не поддерживает работу с "bunzip2",
# тогда придется выполнять работу в два этапа, с использованием конвейера.
# Целью данного примера является разархивирование тарбола (tar.bz2) с исходными текстами ядра.
</pre>
                <br>
                <br>

                <p>Обратите внимание, что в этом контексте <span class="QUOTE">"-"</span> - не
                самостоятельный оператор Bash, а скорее опция,
                распознаваемая некоторыми утилитами UNIX (такими как
                <strong class="COMMAND">tar</strong>, <strong class="COMMAND">cat</strong> и т.п.), которые выводят
                результаты своей работы в <code class="FILENAME">stdout</code>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo "whatever" | cat -</strong></code>
<code class="COMPUTEROUTPUT">whatever</code>
</pre>
                <br>
                <br>

                <p>В случае, когда ожидается имя файла, тогда <span class="QUOTE">"-"</span> перенаправляет
                вывод на <code class="FILENAME">stdout</code> (вспомните пример с <code class="USERINPUT"><strong>tar cf</strong></code>) или
                принимает ввод с <code class="FILENAME">stdin</code>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>file</strong></code>
<code class="COMPUTEROUTPUT">Usage: file [-bciknvzL] [-f namefile] [-m magicfiles] file...</code>
             
</pre>
                Сама по себе команда <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FILEREF">file</a> без параметров завершается с
                сообщением об ошибке. <br>
                <br>

                <p>Добавим символ <span class="QUOTE">"-"</span> и получим более
                полезный результат. Это заставит командный
                интерпретатор ожидать ввода от пользователя.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>file -</strong></code>
<code class="USERINPUT"><strong>abc</strong></code>
<code class="COMPUTEROUTPUT">standard input:              ASCII text</code>

<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>file -</strong></code>
<code class="USERINPUT"><strong>#!/bin/bash</strong></code>
<code class="COMPUTEROUTPUT">standard input:              Bourne-Again shell script text executable</code>
             
</pre>
                Теперь команда принимает ввод пользователя со <code class="FILENAME">stdin</code> и анализирует его. <br>
                <br>

                <p>Используя передачу <code class="FILENAME">stdout</code> по конвейеру другим
                командам, можно выполнять довольно эффектные трюки,
                например <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PREPENDREF">вставка строк в начало
                файла</a>.</p>

                <p>С помощью команды <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DIFFREF">diff</a> -- находить различия между
                одним файлом и <span class="emphasis"><em class="EMPHASIS">частью</em></span> другого:</p>

                <p><code class="USERINPUT"><strong>grep Linux file1 | diff
                file2 -</strong></code></p>

                <p>И наконец пример использования служебного символа
                <code class="REPLACEABLE"><em>"-"</em></code> с
                командой <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TARREF">tar</a>.</p>

                <div class="EXAMPLE">
                  <a name="EX58"></a>

                  <p><strong>Пример 3-4. Резервное архивирование всех
                  файлов, которые были изменены в течение последних
                  суток</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# Резервное архивирование (backup) всех файлов в текущем каталоге,
# которые были изменены в течение последних 24 часов
#+ в тарболл (tarball) (.tar.gz - файл).

BACKUPFILE=backup
archive=${1:-$BACKUPFILE}
#  На случай, если имя архива в командной строке не задано,
#+ т.е. по-умолчанию имя архива -- "backup.tar.gz"

tar cvf - `find . -mtime -1 -type f -print` &gt; $archive.tar
gzip $archive.tar
echo "Каталог $PWD заархивирован в файл \"$archive.tar.gz\"."


#  Stephane Chazelas заметил, что вышеприведенный код будет "падать"
#+ если будет найдено слишком много файлов
#+ или если имена файлов будут содержать символы пробела.

# Им предложен альтернативный код:
# -------------------------------------------------------------------
#   find . -mtime -1 -type f -print0 | xargs -0 tar rvf "$archive.tar"
#      используется версия GNU утилиты "find".


#   find . -mtime -1 -type f -exec tar rvf "$archive.tar" '{}' \;
#         более универсальный вариант, хотя и более медленный,
#         зато может использоваться в других версиях UNIX.
# -------------------------------------------------------------------


exit 0
</pre>
                </div>

                <div class="CAUTION">
                  <table class="CAUTION" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                      <td align="left" valign="top">
                        <p>Могут возникнуть конфликтные ситуации между
                        опреатором перенаправления <span class="QUOTE">"-"</span> и именами
                        файлов, начинающимися с символа <span class="QUOTE">"-"</span>. Поэтому
                        сценарий должен проверять имена файлов и
                        предаварять их префиксом пути, например, <code class="FILENAME">./-FILENAME</code>, <code class="FILENAME">$PWD/-FILENAME</code> или <code class="FILENAME">$PATHNAME/-FILENAME</code>.</p>

                        <p>Если значение переменной начинается с
                        символа <span class="QUOTE">"-"</span>, то это
                        тоже может быть причиной появления ошибок.</p>
<pre class="PROGRAMLISTING">var="-n"
echo $var
# В данном случае команда приобретет вид "echo -n" и ничего не выведет.
</pre>
                        <br>
                        <br>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </dd>

              <dt><span class="TOKEN">-</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>предыдущий рабочий каталог.</strong>
                  [дефис] Команда <strong class="COMMAND">cd -</strong> выполнит переход в
                  предыдущий рабочий каталог, путь к которому хранится
                  в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ENVREF">переменной окружения</a> <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#OLDPWD">$OLDPWD</a> .</p>
                </div>

                <div class="CAUTION">
                  <table class="CAUTION" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                      <td align="left" valign="top">
                        <p>Не путайте оператор <span class="QUOTE">"-"</span>
                        (предыдущего рабочего каталога) с оператором
                        <span class="QUOTE">"-"</span>
                        (переназначения). Еще раз напомню, что
                        интерпретация символа <span class="QUOTE">"-"</span> зависит от
                        контекста, в котором он употребляется.</p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </dd>

              <dt><span class="TOKEN">-</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>Минус.</strong> Знак минус в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AROPS1">арифметических операциях</a>.</p>
                </div>
              </dd>

              <dt><span class="TOKEN">=</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>Символ "равно".</strong> <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EQREF">Оператор присваивания</a></p>
<pre class="PROGRAMLISTING">a=28
echo $a   # 28
</pre>
                  <br>
                  <br>
                </div>

                <p>В зависимости от <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EQUALSIGNREF">контекста применения</a>, символ
                <span class="QUOTE">"<span class="TOKEN">=</span>"</span> может выступать в
                качестве оператора <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SCOMPARISON1">сравнения</a>.</p>
              </dd>

              <dt><span class="TOKEN">+</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>Плюс.</strong> Оператор сложения в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AROPS1">арифметических операциях</a>.</p>
                </div>

                <p>В зависимости от <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PLUSREF">контекста применения</a>, символ <span class="TOKEN">+</span> может выступать как оператор <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REGEXP">регулярного выражения</a>.</p>
              </dd>

              <dt><span class="TOKEN">+</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>Ключ (опция).</strong> Дополнительный флаг
                  для ключей (опций) команд.</p>
                </div>

                <p>Отдельные внешние и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BUILTINREF">встроенные</a> команды используют
                символ <span class="QUOTE">"<span class="TOKEN">+</span>"</span> для разрешения
                некоторой опции, а символ <span class="QUOTE">"<span class="TOKEN">-</span>"</span> -- для
                запрещения.</p>
              </dd>

              <dt><span class="TOKEN">%</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MODULOREF">модуль</a>.</strong> Модуль
                  (остаток от деления) -- <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AROPS1">арифметическая операция</a>.</p>
                </div>

                <p>В зависимости от <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PCTPATREF">контекста применения</a>, символ
                <span class="TOKEN">%</span> может выступать в качестве <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PSUB2">шаблона</a>.</p>
              </dd>

              <dt><span class="TOKEN">~</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>домашний каталог.</strong> [тильда]
                  Соответствует содержимому внутренней переменной <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#HOMEDIRREF">$HOME</a>. <span class="emphasis"><em class="EMPHASIS">~bozo</em></span> -- домашний
                  каталог пользователя bozo, а команда <strong class="COMMAND">ls ~bozo</strong> выведет содержимое
                  его домашнего каталога. <span class="TOKEN">~/</span> -- это домашний каталог
                  текущего пользователя, а команда <strong class="COMMAND">ls ~/</strong> выведет содержимое
                  домашнего каталога текущего пользователя.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo ~bozo</strong></code>
<code class="COMPUTEROUTPUT">/home/bozo</code>

<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo ~</strong></code>
<code class="COMPUTEROUTPUT">/home/bozo</code>

<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo ~/</strong></code>
<code class="COMPUTEROUTPUT">/home/bozo/</code>

<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo ~:</strong></code>
<code class="COMPUTEROUTPUT">/home/bozo:</code>

<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo ~nonexistent-user</strong></code>
<code class="COMPUTEROUTPUT">~nonexistent-user</code>
             
</pre>
                  <br>
                  <br>
                </div>
              </dd>

              <dt><span class="TOKEN">~+</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>текущий рабочий каталог.</strong>
                  Соответствует содержимому внутренней переменной <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PWDREF">$PWD</a>.</p>
                </div>
              </dd>

              <dt><span class="TOKEN">~-</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>предыдущий рабочий каталог.</strong>
                  Соответствует содержимому внутренней переменной <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#OLDPWD">$OLDPWD</a>.</p>
                </div>
              </dd>

              <dt><span class="TOKEN">^</span></dt>

              <dd>
                <div class="FORMALPARA">
                  <p><strong>начало-строки.</strong> В <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REGEXREF">регулярных выражениях</a> символ
                  <span class="QUOTE">"^"</span> задает начало
                  строки текста.</p>
                </div>
              </dd>

              <dt>Управляющий символ</dt>

              <dd>
                <p><a name="CONTROLCHARREF"></a></p>

                <div class="FORMALPARA">
                  <p><strong>изменяет поведение терминала или управляет
                  выводом текста.</strong> Управляющий символ
                  набирается с клавиатуры как комбинация <strong class="KEYCAP">CONTROL</strong> + <strong class="KEYCAP">&lt;клавиша&gt;</strong>.</p>
                </div>

                <ul>
                  <li>
                    <p><code class="USERINPUT"><strong>Ctl-C</strong></code></p>

                    <p>Завершение выполнения процесса.</p>
                  </li>

                  <li>
                    <p><a name="CTLDREF"></a></p>

                    <p><code class="USERINPUT"><strong>Ctl-D</strong></code></p>

                    <p>Выход из командного интерпретатора (log out)
                    (аналог команды <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXITCOMMANDREF">exit</a>).</p>

                    <p><span class="QUOTE">"EOF"</span> (признак
                    конца файла). Этот символ может выступать в
                    качестве завершающего при вводе с <code class="FILENAME">stdin</code>.</p>
                  </li>

                  <li>
                    <p><code class="USERINPUT"><strong>Ctl-G</strong></code></p>

                    <p><span class="QUOTE">"BEL"</span> (звуковой
                    сигнал -- "звонок").</p>
                  </li>

                  <li>
                    <p><code class="USERINPUT"><strong>Ctl-H</strong></code></p>

                    <p>Backspace -- удаление предыдущего символа.</p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Вставка символа Ctl-H в строку.

a="^H^H"                  # Два символа Ctl-H (backspace).
echo "abcdef"             # abcdef
echo -n "abcdef$a "       # abcd f
# Пробел в конце ^              ^ двойной шаг назад.
echo -n "abcdef$a"        # abcdef
# Пробела в конце нет             backspace не работает (почему?).
# Результаты могут получиться совсем не те, что вы ожидаете.
echo; echo
</pre>
                    <br>
                    <br>
                  </li>

                  <li>
                    <p><code class="USERINPUT"><strong>Ctl-J</strong></code></p>

                    <p>Возврат каретки.</p>
                  </li>

                  <li>
                    <p><code class="USERINPUT"><strong>Ctl-L</strong></code></p>

                    <p>Перевод формата (очистка экрана (окна)
                    терминала). Аналогична команде <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CLEARREF">clear</a>.</p>
                  </li>

                  <li>
                    <p><code class="USERINPUT"><strong>Ctl-M</strong></code></p>

                    <p>Перевод строки.</p>
                  </li>

                  <li>
                    <p><code class="USERINPUT"><strong>Ctl-U</strong></code></p>

                    <p>Стирание строки ввода.</p>
                  </li>

                  <li>
                    <p><code class="USERINPUT"><strong>Ctl-Z</strong></code></p>

                    <p>Приостановка процесса.</p>
                  </li>
                </ul>
              </dd>

              <dt>Пробельный символ</dt>

              <dd>
                <p><a name="WHITESPACEREF"></a></p>

                <div class="FORMALPARA">
                  <p><strong>используется как разделитель команд или
                  переменных.</strong> В качестве пробельного символа
                  могут выступать -- собственно пробел (space), символ
                  табуляции, символ перевода строки, символ возврата
                  каретки или комбинация из вышеперечисленных символов.
                  В некоторых случаях, таких как <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WSBAD">присваивание значений переменным</a>,
                  использование пробельных символов недопустимо.</p>
                </div>

                <p>Пустые строки никак не обрабатываются командным
                интерпретатором и могут свободно использоваться для
                визуального выделения отдельных блоков сценария.</p>

                <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IFSREF">$IFS</a> -- переменная специального
                назначения. Содержит символы-разделители полей,
                используемые некоторыми командами. По-умолчанию --
                пробельные символы.</p>
              </dd>
            </dl>
          </div>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="VARIABLES"></a>Глава 4. Переменные и параметры.
          Введение.</h1>

          <p>Переменные -- это одна из основ любого языка
          программирования. Они учавствуют в арифметических операциях,
          в синтаксическом анализе строк и совершенно необходимы для
          абстрагирования каких либо величин с помощью символических
          имен. Физически переменные представляют собой ни что иное как
          участки памяти, в которые записана некоторая информация.</p>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="VARSUBN"></a>4.1. Подстановка переменных</h2>

            <p>Когда интерпретатор встречает в тексте сценария <span class="emphasis"><em class="EMPHASIS">имя</em></span> переменной, то он вместо
            него подставляет <span class="emphasis"><em class="EMPHASIS">значение</em></span> этой переменной.
            Поэтому ссылки на переменные называются <span class="emphasis"><em class="EMPHASIS">подстановкой переменных</em></span>.</p>

            <div class="VARIABLELIST">
              <dl>
                <dt><span class="TOKEN">$</span></dt>

                <dd>
                  <p>Необходимо всегда помнить о различиях между <span class="emphasis"><em class="EMPHASIS">именем</em></span> переменной и ее
                  <span class="emphasis"><em class="EMPHASIS">значением</em></span>. Если <code class="USERINPUT"><strong>variable1</strong></code> --
                  это имя переменной, то <code class="USERINPUT"><strong>$variable1</strong></code>
                  -- это ссылка на ее <span class="emphasis"><em class="EMPHASIS">значение</em></span>. <span class="QUOTE">"Чистые"</span> имена
                  переменных, без префикса <span class="TOKEN">$</span>, могут использоваться только
                  при объявлении переменный, при присваивании
                  переменной некоторого значения, при <span class="emphasis"><em class="EMPHASIS">удалении (сбросе)</em></span>, при
                  <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXPORTREF">экспорте</a> и в особых случаях --
                  когда переменная представляет собой название <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SIGNALD">сигнала</a> (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX76">Пример 29-5</a>). Присваивание может
                  производится с помощью символа <span class="TOKEN">=</span> (например: <span class="emphasis"><em class="EMPHASIS">var1=27</em></span>), инструкцией
                  <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#READREF">read</a> и в заголовке цикла (<span class="emphasis"><em class="EMPHASIS">for var2 in 1 2 3</em></span>).</p>

                  <p><a name="DBLQUO"></a>Заключение ссылки на переменную в
                  двойные кавычки (<span class="TOKEN">" "</span>) никак не
                  сказывается на работе механизма подстановки. Этот
                  случай называется "частичные кавычки",
                  иногда можно встретить название <span class="QUOTE">"нестрогие кавычки"</span>.
                  <a name="SNGLQUO"></a>Одиночные кавычки (<span class="TOKEN">' '</span>) заставляют
                  интерпретатор воспринимать ссылку на переменную как
                  простой набор символов, потому в одинарных кавычках
                  операции подстановки не производятся. Этот случай
                  называется "полные", или <span class="QUOTE">"строгие"</span> кавычки.
                  Дополнительную информацию вы найдете в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#QUOTING">Глава 5</a>.</p>

                  <p>Примечательно, что написание <code class="USERINPUT"><strong>$variable</strong></code>
                  фактически является упрощенной формой написания <code class="USERINPUT"><strong>${variable}</strong></code>.
                  Более строгая форма записи <code class="USERINPUT"><strong>${variable}</strong></code>
                  может с успехом использоваться в тех случаях, когда
                  применение упрощенной формы записи порождает
                  сообщения о синтаксических ошибках (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PARAMETER-SUBSTITUTION">Section 9.3</a>,
                  ниже).</p>

                  <div class="EXAMPLE">
                    <a name="EX9"></a>

                    <p><strong>Пример 4-1. Присваивание значений
                    переменным и подстановка значений
                    переменных</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# Присваивание значений переменным и подстановка значений переменных

a=375
hello=$a

#-------------------------------------------------------------------------
# Использование пробельных символов
# с обеих сторон символа "=" присваивания недопустимо.

#  Если записать "VARIABLE =value",
#+ то интерпретатор попытается выполнить команду "VARIABLE" с параметром "=value".

#  Если записать "VARIABLE= value",
#+ то интерпретатор попытается установить переменную окружения "VARIABLE" в ""
#+ и выполнить команду "value".
#-------------------------------------------------------------------------


echo hello    # Это не ссылка на переменную, выведет строку "hello".

echo $hello
echo ${hello} # Идентично предыдущей строке.

echo "$hello"
echo "${hello}"

echo

hello="A B  C   D"
echo $hello   # A B C D
echo "$hello" # A B  C   D
# Здесь вы сможете наблюдать различия в выводе echo $hello и echo "$hello".
# Заключение ссылки на переменную в кавычки сохраняет пробельные символы.

echo

echo '$hello'  # $hello
# Внутри одинарных кавычек не производится подстановка значений переменных,
#+ т.е. "$" интерпретируется как простой символ.

# Обратите внимание на различия, существующие между этими типами кавычек.


hello=    # Запись пустого значения в переменную.
echo "\$hello (пустое значение) = $hello"
#  Обратите внимание: запись пустого значения -- это не то же самое,
#+ что сброс переменной, хотя конечный результат -- тот же (см. ниже).

# --------------------------------------------------------------

#  Допускается присваивание нескольких переменных в одной строке,
#+ если они отделены пробельными символами.
#  Внимание! Это может снизить читабельность сценария и оказаться непереносимым.

var1=variable1  var2=variable2  var3=variable3
echo
echo "var1=$var1   var2=$var2  var3=$var3"

# Могут возникнуть проблемы с устаревшими версиями "sh".

# --------------------------------------------------------------

echo; echo

numbers="один два три"
other_numbers="1 2 3"
# Если в значениях переменных встречаются пробелы,
# то использование кавычек обязательно.
echo "numbers = $numbers"
echo "other_numbers = $other_numbers"   # other_numbers = 1 2 3
echo

echo "uninitialized_variable = $uninitialized_variable"
# Неинициализированная переменная содержит "пустое" значение.
uninitialized_variable=   #  Объявление неинициализированной переменной
                          #+ (то же, что и присваивание пустого значения, см. выше).
echo "uninitialized_variable = $uninitialized_variable"
                          # Переменная содержит "пустое" значение.

uninitialized_variable=23       # Присваивание.
unset uninitialized_variable    # Сброс.
echo "uninitialized_variable = $uninitialized_variable"
                                # Переменная содержит "пустое" значение.

echo

exit 0
</pre>
                  </div>

                  <div class="CAUTION">
                    <table class="CAUTION" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                        <td align="left" valign="top">
                          <p>Неинициализированная переменная хранит
                          <span class="QUOTE">"пустое"</span>
                          значение - не ноль!. Использование
                          неинициализированных переменных может
                          приводить к ошибкам разного рода в процессе
                          исполнения.</p>

                          <p>Не смотря на это в арифметических
                          операциях допускается использовать
                          неинициализированные переменные.</p>
<pre class="PROGRAMLISTING">echo "$uninitialized"                                # (пустая строка)
let "uninitialized += 5"                             # Прибавить 5.
echo "$uninitialized"                                # 5

#  Заключение:
#  Неинициализированные переменные не имеют значения, однако
#+ в арифметических операциях за значение таких переменных принимается число 0.
#  Это недокументированная (и возможно непереносимая) возможность.
</pre>
                          См. так же <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SELFSOURCE">Пример 11-19</a>.<br>
                          <br>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>
              </dl>
            </div>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="VARASSIGNMENT"></a>4.2. Присваивание значений
            переменным</h2>

            <div class="VARIABLELIST">
              <dl>
                <dt><a name="EQREF"></a><span class="TOKEN">=</span></dt>

                <dd>
                  <p>оператор присваивания (<span class="emphasis"><em class="EMPHASIS">пробельные символы до и после
                  оператора -- недопустимы</em></span>)</p>

                  <div class="CAUTION">
                    <table class="CAUTION" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                        <td align="left" valign="top">
                          <p>Не путайте с операторами сравнения <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EQUALSIGNREF">=</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EQUALREF">-eq</a>!</p>

                          <p>Обратите внимание: символ <span class="TOKEN">=</span> может использоваться
                          как в качестве оператора присваивания, так и
                          в качестве оператора сравнения, конкретная
                          интерпретация зависит от контекста
                          применения.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>

                  <div class="EXAMPLE">
                    <a name="EX15"></a>

                    <p><strong>Пример 4-2. Простое
                    присваивание</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Явные переменные

echo

# Когда перед именем переменной не употребляется символ '$'?
# В операциях присваивания.

# Присваивание
a=879
echo "Значение переменной \"a\" -- $a."

# Присваивание с помощью ключевого слова 'let'
let a=16+5
echo "Значение переменной \"a\" теперь стало равным: $a."

echo

# В заголовке цикла 'for' (своего рода неявное присваивание)
echo -n "Значения переменной \"a\" в цикле: "
for a in 7 8 9 11
do
  echo -n "$a "
done

echo
echo

# При использовании инструкции 'read' (тоже одна из разновидностей присваивания)
echo -n "Введите значение переменной \"a\" "
read a
echo "Значение переменной \"a\" теперь стало равным: $a."

echo

exit 0
</pre>
                  </div>

                  <div class="EXAMPLE">
                    <a name="EX16"></a>

                    <p><strong>Пример 4-3. Присваивание значений
                    переменным простое и замаскированное</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

a=23              # Простейший случай
echo $a
b=$a
echo $b

# Теперь немного более сложный вариант (подстановка команд).

a=`echo Hello!`   # В переменную 'a' попадает результат работы команды 'echo'
echo $a
#  Обратите внимание на восклицательный знак (!) в подстанавливаемой команде
#+ этот вариант не будет работать при наборе в командной строке,
#+ поскольку здесь используется механизм "истории команд" BASH
#  Однако, в сценариях, механизм истории команд запрещен.

a=`ls -l`         # В переменную 'a' записывается результат работы команды 'ls -l'
echo $a           # Кавычки отсутствуют, удаляются лишние пробелы и пустые строки.
echo
echo "$a"         # Переменная в кавычках, все пробелы и пустые строки сохраняются.
                  # (См. главу "Кавычки.")

exit 0
</pre>
                  </div>

                  <p>Присваивание переменных с использованием <span class="TOKEN">$(...)</span> (более современный
                  метод, по сравнению с <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BACKQUOTESREF">обратными кавычками</a>)</p>
<pre class="PROGRAMLISTING"># Взято из /etc/rc.d/rc.local
R=$(cat /etc/redhat-release)
arch=$(uname -m)
</pre>
                  <br>
                  <br>
                </dd>
              </dl>
            </div>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="UNTYPED"></a>4.3. Переменные Bash не имеют типа</h2>

            <p><a name="BVUNTYPED"></a></p>

            <p>В отличие от большинства других языков программирования,
            Bash не производит разделения переменных по <span class="QUOTE">"типам"</span>. По сути,
            переменные Bash являются строковыми переменными, но, в
            зависимости от контекста, Bash допускает целочисленную
            арифметику с переменными. Определяющим фактором здесь
            служит содержимое переменных.</p>

            <div class="EXAMPLE">
              <a name="INTORSTRING"></a>

              <p><strong>Пример 4-4. Целое число или
              строка?</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# int-or-string.sh: Целое число или строка?

a=2334                   # Целое число.
let "a += 1"
echo "a = $a "           # a = 2335
echo                     # Все еще целое число.


b=${a/23/BB}             # замена "23" на "BB".
                         # Происходит трансформация числа в строку.
echo "b = $b"            # b = BB35
declare -i b             # Явное указание типа здесь не поможет.
echo "b = $b"            # b = BB35

let "b += 1"             # BB35 + 1 =
echo "b = $b"            # b = 1
echo

c=BB34
echo "c = $c"            # c = BB34
d=${c/BB/23}             # замена "BB" на "23".
                         # Переменная $d становится целочисленной.
echo "d = $d"            # d = 2334
let "d += 1"             # 2334 + 1 =
echo "d = $d"            # d = 2335
echo

# А что происходит с "пустыми" переменными?
e=""
echo "e = $e"            # e =
let "e += 1"             # Арифметические операции допускают использование "пустых" переменных?
echo "e = $e"            # e = 1
echo                     # "Пустая" переменная становится целочисленной.

# А что происходит с необъявленными переменными?
echo "f = $f"            # f =
let "f += 1"             # Арифметические операции допустимы?
echo "f = $f"            # f = 1
echo                     # Необъявленная переменная трансформируется в целочисленную.



# Переменные Bash не имеют типов.

exit 0
</pre>
            </div>

            <p>Отсутствие типов -- это и благословение и проклятие. С
            одной стороны -- отсутствие типов делает сценарии более
            гибкими (чтобы повеситься -- достаточно иметь веревку!) и
            облегчает чтение кода. С другой -- является источником
            потенциальных ошибок и поощряет привычку к
            "неряшливому" программированию.</p>

            <p>Бремя отслеживания типа той или иной переменной
            полностью лежит на плечах программиста. Bash не будет
            делать это за вас!</p>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="OTHERTYPESV"></a>4.4. Специальные типы
            переменных</h2>

            <div class="VARIABLELIST">
              <dl>
                <dt><code class="REPLACEABLE"><em>локальные
                переменные</em></code></dt>

                <dd>
                  <p>переменные, область видимости которых ограничена
                  <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CODEBLOCKREF">блоком кода</a> или телом
                  функции (см так же <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LOCALVAR">локальные переменные</a> в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FUNCTIONREF">функциях</a>)</p>
                </dd>

                <dt><a name="ENVREF"></a><code class="REPLACEABLE"><em>переменные
                окружения</em></code></dt>

                <dd>
                  <p>переменные, которые затрагивают командную оболочку
                  и порядок взаимодействия с пользователем</p>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p>В более общем контексте, каждый процесс
                          имеет некоторое <span class="QUOTE">"окружение"</span>
                          (среду исполнения), т.е. набор переменных, к
                          которым процесс может обращаться за
                          получением определенной информации. В этом
                          смысле командная оболочка подобна любому
                          другому процессу.</p>

                          <p>Каждый раз, когда запускается командный
                          интерпретатор, для него создаются переменные,
                          соответствующие переменным окружения.
                          Изменение переменных или добавление новых
                          переменных окружения заставляет оболочку
                          обновить свои переменные, и все дочерние
                          процессы (и команды, исполняемые ею)
                          наследуют это окружение.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>

                  <div class="CAUTION">
                    <table class="CAUTION" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                        <td align="left" valign="top">
                          <p>Пространство, выделяемое под переменные
                          окружения, ограничено. Создание слишком
                          большого количества переменных окружения или
                          одной переменной, которая занимает слишком
                          большое пространство, может привести к
                          возникновению определенных проблем.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>eval "`seq 10000 | sed -e 's/.*/export var&amp;=ZZZZZZZZZZZZZZ/'`"</strong></code>

<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>du</strong></code>
<code class="COMPUTEROUTPUT">bash: /usr/bin/du: Argument list too long</code>
                 
</pre>
                          <br>
                          <br>

                          <p>(Спасибо S. C. за вышеприведенный пример и
                          пояснения.)</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>

                  <p>Если сценарий изменяет переменные окружения, то
                  они должны <span class="QUOTE">"экспортироваться"</span>,
                  т.е передаваться окружению, локальному по отношению к
                  сценарию. Эта функция возложена на команду <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXPORTREF">export</a>.</p>
                  <a name="CHILDREF"></a>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p>Сценарий может <strong class="COMMAND">экспортировать</strong>
                          переменные только дочернему процессу, т.е.
                          командам и процессам запускаемым из данного
                          сценария. Сценарий, запускаемый из командной
                          строки <code class="REPLACEABLE"><em>не может</em></code>
                          экспортировать переменные "на верх"
                          командной оболочке. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FORKREF">Дочерний процесс</a> не
                          может экспортировать переменные родительскому
                          процессу.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>

                  <p>---</p>
                </dd>

                <dt><a name="POSPARAMREF1"></a><code class="REPLACEABLE"><em>позиционные
                параметры</em></code></dt>

                <dd>
                  <p>аргументы, передаваемые скрипту из командной
                  строки -- $0, $1, $2, $3..., где $0 -- это название
                  файла сценария, $1 -- это первый аргумент, $2 --
                  второй, $3 -- третий и так далее. <a name="AEN1772" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN1772"><span class="footnote">[13]</span></a> <a name="BRACKETNOTATION"></a>Аргументы, следующие за
                  $9, должны заключаться в фигурные скобки, например:
                  ${10}, ${11}, ${12}.</p>

                  <p>Специальные переменные <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#APPREF">$* и $@</a> содержат <span class="emphasis"><em class="EMPHASIS">все</em></span> позиционные
                  параметры (аргументы командной строки).</p>

                  <div class="EXAMPLE">
                    <a name="EX17"></a>

                    <p><strong>Пример 4-5. Позиционные
                    параметры</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# Команда вызова сценария должна содержать по меньшей мере 10 параметров, например
# ./scriptname 1 2 3 4 5 6 7 8 9 10
MINPARAMS=10

echo

echo "Имя файла сценария: \"$0\"."
# Для текущего каталога добавит ./
echo "Имя файла сценария: \"`basename $0`\"."
# Добавит путь к имени файла (см. 'basename')

echo

if [ -n "$1" ]              # Проверяемая переменная заключена в кавычки.
then
 echo "Параметр #1: $1"     # необходимы кавычки для экранирования символа #
fi

if [ -n "$2" ]
then
 echo "Параметр #2: $2"
fi

if [ -n "$3" ]
then
 echo "Параметр #3: $3"
fi

# ...


if [ -n "${10}" ]  # Параметры, следующие за $9 должны заключаться в фигурные скобки
then
 echo "Параметр #10: ${10}"
fi

echo "-----------------------------------"
echo "Все аргументы командной строки: "$*""

if [ $# -lt "$MINPARAMS" ]
then
  echo
  echo "Количество аргументов командной строки должно быть не менее $MINPARAMS !"
fi

echo

exit 0
</pre>
                  </div>

                  <p><span class="emphasis"><em class="EMPHASIS">Скобочная нотация</em></span>
                  позиционных параметров дает довольно простой способ
                  обращения к <span class="emphasis"><em class="EMPHASIS">последнему</em></span> аргументу,
                  переданному в сценарий из командной строки. Такой
                  способ подразумевает использование <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#VARREFNEW">косвенной адресации</a>.</p>
<pre class="PROGRAMLISTING">args=$#           # Количество переданных аргументов.
lastarg=${!args}  # Обратите внимание: lastarg=${!$#} неприменимо.
</pre>
                  <br>
                  <br>

                  <p>В сценарии можно предусмотреть различные варианты
                  развития событий, в зависимости от имени сценария.
                  Для этого сценарий должен проанализировать аргумент
                  <code class="VARNAME">$0</code> -- имя файла сценария. Это
                  могут быть и имена символических ссылок на файл
                  сценария.</p>

                  <div class="TIP">
                    <table class="TIP" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/tip.gif" hspace="5" alt="Tip"></td>

                        <td align="left" valign="top">
                          <p>Если сценарий ожидает передачи аргументов
                          в командной строке, то при их отсутствии он
                          получит "пустые" переменные, что
                          может вызвать нежелательный побочный эффект.
                          Один из способов борьбы с подобными ошибками
                          -- добавить дополнительный символ в обеих
                          частях операции присваивания, где
                          используются аргументы командной строки.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
<pre class="PROGRAMLISTING">variable1_=$1_
# Это предотвратит появление ошибок, даже при отсутствии входного аргумента.

critical_argument01=$variable1_

# Дополнительные символы всегда можно "убрать" позднее.
# Это может быть сделано примерно так:
variable1=${variable1_/_/}   # Побочный эффект возникает только если имя переменной
                             # $variable1_ будет начинаться с символа "_".
# Здесь используется один из вариантов подстановки параметров, обсуждаемых в Главе 9.
# Отсутствие шаблона замены приводит к удалению.

# Более простой способ заключается
#+ в обычной проверке наличия позиционного параметра.
if [ -z $1 ]
then
  exit $POS_PARAMS_MISSING
fi
</pre>

                  <p>---</p>

                  <div class="EXAMPLE">
                    <a name="EX18"></a>

                    <p><strong>Пример 4-6. wh, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WHOISREF">whois</a> выяснение имени
                    домена</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# Команда 'whois domain-name' выясняет имя домена на одном из 3 серверов:
#                    ripe.net, cw.net, radb.net

# Разместите этот скрипт под именем 'wh' в каталоге /usr/local/bin

# Требуемые символические ссылки:
# ln -s /usr/local/bin/wh /usr/local/bin/wh-ripe
# ln -s /usr/local/bin/wh /usr/local/bin/wh-cw
# ln -s /usr/local/bin/wh /usr/local/bin/wh-radb


if [ -z "$1" ]
then
  echo "Порядок использования: `basename $0` [domain-name]"
  exit 65
fi

case `basename $0` in
# Проверка имени скрипта и, соответственно, имени сервера
    "wh"     ) whois $1@whois.ripe.net;;
    "wh-ripe") whois $1@whois.ripe.net;;
    "wh-radb") whois $1@whois.radb.net;;
    "wh-cw"  ) whois $1@whois.cw.net;;
    *        ) echo "Порядок использования: `basename $0` [domain-name]";;
esac

exit 0
</pre>
                  </div>

                  <p>---</p>

                  <p><a name="SHIFTREF"></a></p>

                  <p>Команда <strong class="COMMAND">shift</strong> "сдвигает"
                  позиционные параметры, в результате чего парметры
                  "сдвигаются" на одну позицию влево.</p>

                  <p><code class="VARNAME">$1</code> &lt;--- <code class="VARNAME">$2</code>, <code class="VARNAME">$2</code> &lt;--- <code class="VARNAME">$3</code>, <code class="VARNAME">$3</code> &lt;--- <code class="VARNAME">$4</code>, и т.д.</p>

                  <p>Прежний аргумент <code class="VARNAME">$1</code> теряется, но аргумент <span class="emphasis"><em class="EMPHASIS"><code class="VARNAME">$0</code> (имя файла сценария)
                  остается без изменений</em></span>. Если вашему
                  сценарию передается большое количество входных
                  аргументов, то команда <strong class="COMMAND">shift</strong> позволит вам получить
                  доступ к аргументам, с порядковым номером больше <code class="LITERAL">9</code>, без использования <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BRACKETNOTATION">{фигурных скобок}</a>.</p>

                  <div class="EXAMPLE">
                    <a name="EX19"></a>

                    <p><strong>Пример 4-7. Использование команды
                    shift</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Использование команды 'shift' с целью перебора всех аргументов командной строки.

#  Назовите файл с этим сценарием, например "shft",
#+ и вызовите его с набором аргументов, например:
#          ./shft a b c def 23 skidoo

until [ -z "$1" ]  # До тех пор пока не будут разобраны все входные аргументы...
do
  echo -n "$1 "
  shift
done

echo               # Дополнительная пустая строка.

exit 0
</pre>
                  </div>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p>Команда <strong class="COMMAND">shift</strong> может
                          применяться и к входным аргументам <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FUNCTIONREF">функций</a>. См. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MULTIPLICATION">Пример 33-10</a>.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>
              </dl>
            </div>
          </div>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="QUOTING"></a>Глава 5. Кавычки</h1>

          <p><a name="QUOTINGREF"></a></p>

          <p>Кавычки, ограничивающие строки с обеих сторон, служат для
          предотвращения интерпретации специальных символов, которые
          могут находиться в строке. (Символ называется
          "специальным", если он несет дополнительную
          смысловую нагрузку, например символ <span class="TOKEN">шаблона</span> -- <span class="TOKEN">*</span>.)</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>ls -l [Vv]*</strong></code>
<code class="COMPUTEROUTPUT">-rw-rw-r--    1 bozo  bozo       324 Apr  2 15:05 VIEWDATA.BAT
 -rw-rw-r--    1 bozo  bozo       507 May  4 14:25 vartrace.sh
 -rw-rw-r--    1 bozo  bozo       539 Apr 14 17:11 viewdata.sh</code>

<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>ls -l '[Vv]*'</strong></code>
<code class="COMPUTEROUTPUT">ls: [Vv]*: No such file or directory</code>
</pre>
          <br>
          <br>

          <div class="NOTE">
            <table class="NOTE" width="100%" border="0">
              <tbody><tr>
                <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                <td align="left" valign="top">
                  <p>Некоторые программы и утилиты могут вызываться с
                  дополнительными параметрами, содержащими специальными
                  символы, поэтому очень важно предотвратить
                  интерпретацию передаваемых параметров командной
                  оболочкой, позволяя сделать это вызываемой
                  программой.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>grep '[Пп]ервая' *.txt</strong></code>
<code class="COMPUTEROUTPUT">file1.txt:Это первая строка в file1.txt.
 file2.txt:Это Первая строка в file2.txt.</code>
</pre>
                  <br>
                  <br>

                  <p>Примечательно, что "не окавыченный"
                  вариант команды <code class="USERINPUT"><strong>grep [Пп]ервая
                  *.txt</strong></code> будет правильно исполняться в
                  Bash, но не в <strong class="COMMAND">tcsh</strong>.</p>
                </td>
              </tr>
            </tbody></table>
          </div>

          <p>Вообще, желательно использовать двойные кавычки (<span class="TOKEN">" "</span>) при обращении к
          переменным. Это предотвратит интерпретацию специальных
          символов, которые могут содержаться в именах переменных, за
          исключением <span class="TOKEN">$</span>, <span class="TOKEN">`</span> (обратная кавычка) и <span class="TOKEN">\</span> (escape -- обратный слэш). <a name="AEN1882" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN1882"><span class="footnote">[14]</span></a> То, что символ <span class="TOKEN">$</span> попал в разряд исключений, позволяет
          выполнять обращение к переменным внутри строк, ограниченных
          двойными кавычками (<code class="REPLACEABLE"><em>"$variable"</em></code>),
          т.е. выполнять подстановку значений переменных (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX9">Пример 4-1</a>, выше).</p>

          <p>Двойные кавычки могут быть использованы для предотвращения
          разбиения строки на слова. <a name="AEN1906" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN1906"><span class="footnote">[15]</span></a> Заключение строки в кавычки
          приводит к тому, что она передается как один аргумент, даже
          если она содержит <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WHITESPACEREF">пробельные символы</a> -
          разделители.</p>
<pre class="PROGRAMLISTING">variable1="a variable containing five words"
COMMAND This is $variable1    # Исполнение COMMAND с 7 входными аргументами:
# "This" "is" "a" "variable" "containing" "five" "words"

COMMAND "This is $variable1"  # Исполнение COMMAND с одним входным аргументом:
# "This is a variable containing five words"


variable2=""    # Пустая переменная.

COMMAND $variable2 $variable2 $variable2        # Исполнение COMMAND без аргументов.
COMMAND "$variable2" "$variable2" "$variable2"  # Исполнение COMMAND с 3 "пустыми" аргументами.
COMMAND "$variable2 $variable2 $variable2"      # Исполнение COMMAND с 1 аргументом (и 2 пробелами).

# Спасибо S.C.
</pre>
          <br>
          <br>

          <div class="TIP">
            <table class="TIP" width="100%" border="0">
              <tbody><tr>
                <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/tip.gif" hspace="5" alt="Tip"></td>

                <td align="left" valign="top">
                  <p>Заключение в кавычки аргументов команды <strong class="COMMAND">echo</strong> необходимо только в
                  том случае, когда разбиение на отдельные слова
                  сопряжено с определенными трудностями.</p>
                </td>
              </tr>
            </tbody></table>
          </div>

          <div class="EXAMPLE">
            <a name="WEIRDVARS"></a>

            <p><strong>Пример 5-1. Вывод "причудливых"
            переменных</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# weirdvars.sh: Вывод "причудливых" переменных

var="'(]\\{}\$\""
echo $var        # '(]\{}$"
echo "$var"      # '(]\{}$"     Никаких различий.

echo

IFS='\'
echo $var        # '(] {}$"     \ символ-разделитель преобразован в пробел.
echo "$var"      # '(]\{}$"

# Примеры выше предоставлены S.C.

exit 0
</pre>
          </div>

          <p>Одиночные кавычки (<span class="TOKEN">' '</span>) схожи по своему действию с
          двойными кавычками, только не допускают обращение к
          переменным, поскольку специальный символ "$" внутри
          одинарных кавычек воспринимается как обычный символ. Внутри
          одиночных кавычек, <span class="emphasis"><em class="EMPHASIS">любой</em></span> специальный символ, за
          исключением <span class="TOKEN">'</span>, интерпретируется как простой
          символ. Одиночные кавычки (<span class="QUOTE">"строгие, или полные
          кавычки"</span>) следует рассматривать как более строгий
          вариант чем двойные кавычки (<span class="QUOTE">"нестрогие, или неполные
          кавычки"</span>).</p>

          <div class="NOTE">
            <table class="NOTE" width="100%" border="0">
              <tbody><tr>
                <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                <td align="left" valign="top">
                  <p>Поскольку внутри одиночных кавычек даже
                  экранирующий (<span class="TOKEN">\</span>) символ воспринимается как
                  обычный символ, попытка вывести одиночную кавычку
                  внутри строки, ограниченной одинарными кавычками, не
                  даст желаемого результата.</p>
<pre class="PROGRAMLISTING">echo "Why can't I write 's between single quotes"

echo

# Обходной метод.
echo 'Why can'\''t I write '"'"'s between single quotes'
#    |-------|  |----------|   |-----------------------|
# Три строки, ограниченных одинарными кавычками,
# и экранированные одиночные кавычки между ними.

# Пример любезно предоставлен Stephane Chazelas.
</pre>
                  <br>
                  <br>
                </td>
              </tr>
            </tbody></table>
          </div>

          <p><a name="ESCP"></a><em class="FIRSTTERM">Экранирование</em> -- это способ
          заключения в кавычки одиночного символа. Экранирующий (<span class="TOKEN">escape</span>) символ (<span class="TOKEN">\</span>) сообщает интерпретатору, что
          следующий за ним символ должен восприниматься как обычный
          символ.</p>

          <div class="CAUTION">
            <table class="CAUTION" width="100%" border="0">
              <tbody><tr>
                <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                <td align="left" valign="top">
                  <p>С отдельными командами и утилитами, такими как <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ECHOREF">echo</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SEDREF">sed</a>, экранирующий символ может
                  применяться для получения обратного эффекта - когда
                  обычные символы при экранировании приобретают
                  специальное значение.</p>
                </td>
              </tr>
            </tbody></table>
          </div>

          <div class="VARIABLELIST">
            <p><strong><a name="SPM"></a>Специальное назначение некоторых
            экранированных символов</strong></p>

            <dl>
              <dt>используемых совместно с <strong class="COMMAND">echo</strong> и <strong class="COMMAND">sed</strong></dt>

              <dt><span class="TOKEN">\n</span></dt>

              <dd>
                <p>перевод строки (новая строка)</p>
              </dd>

              <dt><span class="TOKEN">\r</span></dt>

              <dd>
                <p>перевод каретки</p>
              </dd>

              <dt><span class="TOKEN">\t</span></dt>

              <dd>
                <p>табуляция</p>
              </dd>

              <dt><span class="TOKEN">\v</span></dt>

              <dd>
                <p>вертикальная табуляция</p>
              </dd>

              <dt><span class="TOKEN">\b</span></dt>

              <dd>
                <p>забой (backspace)</p>
              </dd>

              <dt><span class="TOKEN">\a</span></dt>

              <dd>
                <p><span class="QUOTE">"звонок"</span> (сигнал)</p>
              </dd>

              <dt><span class="TOKEN">\0xx</span></dt>

              <dd>
                <p>ASCII-символ с кодом <code class="REPLACEABLE"><em>0xx</em></code> в восьмеричном
                виде)</p>

                <div class="EXAMPLE">
                  <a name="ESCAPED"></a>

                  <p><strong>Пример 5-2. Экранированные
                  символы</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# escaped.sh: экранированные символы

echo; echo

echo "\v\v\v\v"      # Вывод последовательности символов \v\v\v\v.
# Для вывода экранированных символов следует использовать ключ -e.
echo "============="
echo "ВЕРТИКАЛЬНАЯ ТАБУЛЯЦИЯ"
echo -e "\v\v\v\v"   # Вывод 4-х вертикальных табуляций.
echo "=============="

echo "КАВЫЧКИ"
echo -e "\042"       # Выводит символ " (кавычки с восьмеричным кодом ASCII 42).
echo "=============="

# Конструкция $'\X' делает использование ключа -e необязательным.
echo; echo "НОВАЯ СТРОКА И ЗВОНОК"
echo $'\n'           # Перевод строки.
echo $'\a'           # Звонок (сигнал).

echo "==============="
echo "КАВЫЧКИ"
# Bash версии 2 и выше допускает использование конструкции $'\nnn'.
# Обратите внимание: здесь под '\nnn' подразумевается восьмеричное значение.
echo $'\t \042 \t'   # Кавычки (") окруженные табуляцией.

# В конструкции $'\xhhh' допускается использовать и шестнадцатеричные значения.
echo $'\t \x22 \t'  # Кавычки (") окруженные табуляцией.
# Спасибо Greg Keraunen, за это примечание.
# Ранние версии Bash допускали употребление конструкции в виде '\x022'.
echo "==============="
echo


# Запись ASCII-символов в переменную.
# ----------------------------------------
quote=$'\042'        # запись символа " в переменную.
echo "$quote Эта часть строки ограничена кавычками, $quote а эта -- нет."

echo

# Конкатенация ASCII-символов в переменную.
triple_underline=$'\137\137\137'  # 137 -- это восьмеричный код символа '_'.
echo "$triple_underline ПОДЧЕРКИВАНИЕ $triple_underline"

echo

ABC=$'\101\102\103\010'           # 101, 102, 103 это  A, B и C соответственно.
echo $ABC

echo; echo

escape=$'\033'                    # 033 -- восьмеричный код экранирующего символа.
echo "\"escape\" выводится как $escape"
#                                   вывод отсутствует.

echo; echo

exit 0
</pre>
                </div>

                <p>Еще один пример использования конструкции <code class="USERINPUT"><strong>$' '</strong></code>
                вы найдете в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX77">Пример 34-1</a>.</p>
              </dd>

              <dt><span class="TOKEN">\"</span></dt>

              <dd>
                <p>кавычки</p>
<pre class="PROGRAMLISTING">echo "Привет"                    # Привет
echo "Он сказал: \"Привет\"."    # Он сказал: "Привет".
</pre>
                <br>
                <br>
              </dd>

              <dt><span class="TOKEN">\$</span></dt>

              <dd>
                <p>символ доллара (если за комбинацией символов \$
                следует имя переменной, то она не будет
                разыменована)</p>
<pre class="PROGRAMLISTING">echo "\$variable01"  # выведет $variable01
</pre>
                <br>
                <br>
              </dd>

              <dt><span class="TOKEN">\\</span></dt>

              <dd>
                <p>обратный слэш</p>
<pre class="PROGRAMLISTING">echo "\\"  # выведет \
</pre>
                <br>
                <br>
              </dd>
            </dl>
          </div>

          <div class="NOTE">
            <table class="NOTE" width="100%" border="0">
              <tbody><tr>
                <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                <td align="left" valign="top">
                  <p>Поведение символа <span class="TOKEN">\</span> сильно зависит от того
                  экранирован ли он, ограничен ли кавычками или
                  находится внутри конструкции <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COMMANDSUBREF">подстановки команды</a> или во
                  <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#HEREDOCREF">вложенном документе</a>.</p>
<pre class="PROGRAMLISTING">                      #  Простое экранирование и кавычки
echo \z               #  z
echo \\z              # \z
echo '\z'             # \z
echo '\\z'            # \\z
echo "\z"             # \z
echo "\\z"            # \z

                      #  Подстановка команды
echo `echo \z`        #  z
echo `echo \\z`       #  z
echo `echo \\\z`      # \z
echo `echo \\\\z`     # \z
echo `echo \\\\\\z`   # \z
echo `echo \\\\\\\z`  # \\z
echo `echo "\z"`      # \z
echo `echo "\\z"`     # \z

                      # Встроенный документ
cat &lt;&lt;EOF
\z
EOF                   # \z

cat &lt;&lt;EOF
\\z
EOF                   # \z

# Эти примеры предоставил Stephane Chazelas.
</pre>
                  <br>
                  <br>

                  <p>Отдельные символы в строке, которая записывается в
                  переменную, могут быть экранированы, исключение
                  составляет сам экранирующий символ.</p>
<pre class="PROGRAMLISTING">variable=\
echo "$variable"
# Не работает - дает сообщение об ошибке:
# test.sh: : command not found
# В "чистом" виде экранирующий (escape) символ не может быть записан в переменную.
#
#  Фактически, в данном примере, происходит экранирование символа перевода строки
#+ в результате получается такая команда:   variable=echo "$variable"
#+                                          ошибочное присваивание

variable=\
23skidoo
echo "$variable"    #  23skidoo
                    #  Здесь все в порядке, поскольку вторая строка
                    #+ является нормальным, с точки зрения присваивания, выражением.

variable=\
#        \^    За escape-символом следует пробел
echo "$variable"        # пробел

variable=\\
echo "$variable"        # \

variable=\\\
echo "$variable"
# Не работает - сообщение об ошибке:
# test.sh: \: command not found
#
#  Первый escape-символ экранирует второй, а третий оказывается неэкранированным,
#+ результат тот же, что и в первом примере.

variable=\\\\
echo "$variable"        # \\
                        # Второй и четвертый escape-символы экранированы.
                        # Это нормально.
</pre>
                  <br>
                  <br>
                </td>
              </tr>
            </tbody></table>
          </div>

          <p>Экранирование пробелов предотвращает разбиение списка
          аргументов командной строки на отдельные аргументы.</p>
<pre class="PROGRAMLISTING">file_list="/bin/cat /bin/gzip /bin/more /usr/bin/less /usr/bin/emacs-20.7"
# Список файлов как аргумент(ы) командной строки.

# Добавить два файла в список и вывести список.
ls -l /usr/X11R6/bin/xsetroot /sbin/dump $file_list

echo "-------------------------------------------------------------------------"

# Что произойдет, если экранировать пробелы в списке?
ls -l /usr/X11R6/bin/xsetroot\ /sbin/dump\ $file_list
# Ошибка: первые три файла будут "слиты" воедино
# и переданы команде 'ls -l' как один аргумент
# потому что два пробела, разделяющие аргументы (слова) -- экранированы.
</pre>
          <br>
          <br>

          <p>Кроме того, <span class="TOKEN">escape</span>-символ позволяет писать
          многострочные команды. Обычно, каждая команда занимает одну
          строку, но <span class="TOKEN">escape</span>-символ позволяет <span class="emphasis"><em class="EMPHASIS">экранировать символ перевода
          строки</em></span>, в результате чего одна команда может
          занимать несколько строк.</p>
<pre class="PROGRAMLISTING">(cd /source/directory &amp;&amp; tar cf - . ) | \
(cd /dest/directory &amp;&amp; tar xpvf -)
# Команда копирования дерева каталогов.
# Разбита на две строки для большей удобочитаемости.

# Альтернативный вариант:
tar cf - -C /source/directory . |
tar xpvf - -C /dest/directory
# См. примечание ниже.
# (Спасибо Stephane Chazelas.)
</pre>

          <div class="NOTE">
            <table class="NOTE" width="100%" border="0">
              <tbody><tr>
                <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                <td align="left" valign="top">
                  <p>Если строка сценария заканчивается символом
                  создания конвейера <span class="TOKEN">|</span>, то необходимость в
                  применении символа <span class="TOKEN">\</span>, для экранирования перевода
                  строки, отпадает. Тем не менее, считается хорошим
                  тоном, всегда использовать символ "\" в
                  конце промежуточных строк многострочных команд.</p>
                </td>
              </tr>
            </tbody></table>
          </div>
          <br>
          <br>
<pre class="PROGRAMLISTING">echo "foo
bar"
#foo
#bar

echo

echo 'foo
bar'    # Никаких различий.
#foo
#bar

echo

echo foo\
bar     # Перевод строки экранирован.
#foobar

echo

echo "foo\
bar"     # Внутри "нестрогих" кавычек символ "\" интерпретируется как экранирующий.
#foobar

echo

echo 'foo\
bar'     # В "строгих" кавычках обратный слэш воспринимается как обычный символ.
#foo\
#bar

# Примеры предложены Stephane Chazelas.
</pre>
          <br>
          <br>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="EXIT-STATUS"></a>Глава 6. Завершение и код
          завершения</h1>

          <table border="0" width="100%" cellspacing="0" cellpadding="0" class="EPIGRAPH">
            <tbody><tr>
              <td width="45%">&nbsp;</td>

              <td width="45%" align="left" valign="top">
                <p><em>...эта часть Bourne shell покрыта мраком, тем не
                менее все пользуются ею.</em></p>
              </td>
            </tr>

            <tr>
              <td width="45%">&nbsp;</td>

              <td width="45%" align="right" valign="top"><em><span class="ATTRIBUTION">Chet Ramey</span></em></td>
            </tr>
          </tbody></table>

          <p><a name="EXITCOMMANDREF"></a>Команда <strong class="COMMAND">exit</strong> может использоваться для
          завершения работы сценария, точно так же как и в программах
          на языке C. Кроме того, она может возвращать некоторое
          значение, которое может быть проанализировано вызывающим
          процессом.</p>

          <p><a name="EXITSTATUSREF"></a>Каждая команда возвращает <em class="FIRSTTERM">код завершения</em> (иногда код завершения
          называют <em class="FIRSTTERM">возвращаемым значением</em> ). В случае
          успеха команда должна возвращать <span class="RETURNVALUE">0</span>, а в случае ошибки -- <span class="RETURNVALUE">ненулевое</span> значение, которое, как
          правило, интерпретируется как код ошибки. Практически все
          команды и утилиты UNIX возвращают <span class="RETURNVALUE">0</span> в случае успешного завершения,
          но имеются и исключения из правил.</p>

          <p>Аналогичным образом ведут себя функции, расположенные
          внутри сценария, и сам сценарий, возвращая код завершения.
          Код, возвращаемый функцией или сценарием, определяется кодом
          возврата последней команды. Команде <code class="USERINPUT"><strong>exit</strong></code> можно явно
          указать код возврата, в виде: <code class="USERINPUT"><strong>exit</strong></code> <span class="RETURNVALUE"><code class="REPLACEABLE"><em>nnn</em></code></span>, где <span class="RETURNVALUE"><code class="REPLACEABLE"><em>nnn</em></code></span> -- это код
          возврата (число в диапазоне <span class="RETURNVALUE">0</span> - <span class="RETURNVALUE">255</span>).</p>

          <div class="NOTE">
            <table class="NOTE" width="100%" border="0">
              <tbody><tr>
                <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                <td align="left" valign="top">
                  <p>Когда работа сценария завершается командой <strong class="COMMAND">exit</strong> без параметров, то код
                  возврата сценария определяется кодом возврата
                  последней исполненной командой.</p>
                </td>
              </tr>
            </tbody></table>
          </div>

          <p><a name="EXSREF"></a></p>

          <p>Код возврата последней команды хранится в специальной
          переменной <code class="VARNAME">$?</code>. После исполнения кода функции,
          переменная <code class="VARNAME">$?</code> хранит код завершения последней
          команды, исполненной в функции. Таким способом в Bash
          передается <span class="QUOTE">"значение, возвращаемое"</span>
          функцией. После завершения работы сценария, код возврата
          можно получить, обратившись из командной строки к переменной
          <code class="VARNAME">$?</code>, т.е. это будет код возврата
          последней команды, исполненной в сценарии.</p>

          <div class="EXAMPLE">
            <a name="EX5"></a>

            <p><strong>Пример 6-1. завершение / код
            завершения</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

echo hello
echo $?    # код возврата = 0, поскольку команда выполнилась успешно.

lskdf      # Несуществующая команда.
echo $?    # Ненулевой код возврата, поскольку команду выполнить не удалось.

echo

exit 113   # Явное указание кода возврата 113.
           # Проверить можно, если набрать в командной строке "echo $?"
           # после выполнения этого примера.

#  В соответствии с соглашениями, 'exit 0' указывает на успешное завершение,
#+ в то время как ненулевое значение означает ошибку.
</pre>
          </div>

          <p>Переменная <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#XSTATVARREF">$?</a> особенно полезна, когда
          необходимо проверить результат исполнения команды (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FILECOMP">Пример 12-27</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LOOKUP">Пример 12-13</a>).</p>

          <div class="NOTE">
            <table class="NOTE" width="100%" border="0">
              <tbody><tr>
                <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                <td align="left" valign="top">
                  <p>Символ <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#NOTREF">!</a>, может выступать как логическое
                  "НЕ" для инверсии <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXITSTATUSREF">кода возврата</a>.</p>

                  <div class="EXAMPLE">
                    <a name="NEGCOND"></a>

                    <p><strong>Пример 6-2. Использование символа <span class="TOKEN">!</span> для логической инверсии
                    кода возврата</strong></p>
<pre class="PROGRAMLISTING">true  # встроенная команда "true".
echo "код возврата команды \"true\" = $?"     # 0

! true
echo "код возврата команды \"! true\" = $?"   # 1
# Обратите внимание: символ "!" от команды необходимо отделять пробелом.
#    !true   вызовет сообщение об ошибке "command not found"

# Спасибо S.C.
</pre>
                  </div>
                  <br>
                  <br>
                </td>
              </tr>
            </tbody></table>
          </div>

          <div class="CAUTION">
            <table class="CAUTION" width="100%" border="0">
              <tbody><tr>
                <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                <td align="left" valign="top">
                  <p>В отдельных случаях коды возврата должны иметь <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXITCODESREF">предопределенные значения</a> и
                  не должны задаваться пользователем.</p>
                </td>
              </tr>
            </tbody></table>
          </div>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="TESTS"></a>Глава 7. Проверка условий</h1>

          <p><a name="IFTHEN"></a></p>

          <p>практически любой язык программирования включает в себя
          условные операторы, предназначенные для проверки условий,
          чтобы выбрать тот или иной путь развития событий в
          зависимости от этих условий. В Bash, для проверки условий,
          имеется команда <strong class="COMMAND">test</strong>, различного вида скобочные
          операторы и условный оператор <strong class="COMMAND">if/then</strong>.</p>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="TESTCONSTRUCTS"></a>7.1. Конструкции проверки
            условий</h2>

            <p><a name="TESTCONSTRUCTS1"></a></p>

            <ul>
              <li>
                <p>Оператор <strong class="COMMAND">if/then</strong> проверяет -- является
                ли <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXITSTATUSREF">код завершения</a> списка команд
                <span class="RETURNVALUE">0</span> (поскольку 0 означает
                <span class="QUOTE">"успех"</span>), и если это
                так, то выполняет одну, или более, команд, следующие за
                словом then.</p>
              </li>

              <li>
                <p>Существует специальная команда -- <strong class="COMMAND">[</strong> (<a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LEFTBRACKET">левая квадратная скобка</a>). Она
                является синонимом команды <strong class="COMMAND">test</strong>, и является <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BUILTINREF">встроенной</a> командой (т.е. более
                эффективной, в смысле производительности). Эта команда
                воспринимает свои аргументы как выражение сравнения или
                как файловую проверку и возвращает код завершения в
                соответствии с результатами проверки (0 -- истина, 1 --
                ложь).</p>
              </li>

              <li>
                <p>Начиная с версии 2.02, Bash предоставляет в
                распоряжение программиста конструкцию <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DBLBRACKETS">[[ ... ]]</a> <span class="emphasis"><em class="EMPHASIS">расширенный вариант команды
                test</em></span>, которая выполняет сравнение способом
                более знакомым программистам, пишущим на других языках
                программирования. Обратите внимание: <strong class="COMMAND">[[</strong> -- это <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#KEYWORDREF">зарезервированное слово</a>, а не
                команда.</p>

                <p>Bash исполняет <code class="USERINPUT"><strong>[[ $a -lt $b
                ]]</strong></code> как один элемент, который имеет код
                возврата.</p>

                <p>Круглые скобки <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DBLPARENS">(( ... ))</a> и предложение <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LETREF">let ...</a> так же возвращают код <span class="RETURNVALUE">0</span>, если результатом
                арифметического выражения является ненулевое значение.
                Таким образом, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ARITHEXPREF">арифметические выражения</a> могут
                учавствовать в операциях сравнения.</p>
<pre class="PROGRAMLISTING">Предложение let "1&lt;2" возвращает 0 (так как результат сравнения "1&lt;2" -- "1", или "истина")
(( 0 &amp;&amp; 1 )) возвращает 1 (так как результат операции "0 &amp;&amp; 1" -- "0", или "ложь")
</pre>
                <br>
                <br>
              </li>

              <li>
                <p>Условный оператор <strong class="COMMAND">if</strong> проверяет код завершения
                любой команды, а не только результат выражения,
                заключенного в квадратные скобки.</p>
<pre class="PROGRAMLISTING">if cmp a b &amp;&gt; /dev/null  # Подавление вывода.
then echo "Файлы a и b идентичны."
else echo "Файлы a и b имеют различия."
fi

if grep -q Bash file
then echo "Файл содержит, как минимум, одно слово Bash."
fi

if COMMAND_WHOSE_EXIT_STATUS_IS_0_UNLESS_ERROR_OCCURRED
then echo "Команда выполнена успешно."
else echo "Обнаружена ошибка при выполнении команды."
fi
</pre>
                <br>
                <br>
              </li>

              <li>
                <p>Оператор <strong class="COMMAND">if/then</strong> допускает наличие
                вложенных проверок.</p>
<pre class="PROGRAMLISTING">if echo "Следующий *if* находится внутри первого *if*."

  if [[ $comparison = "integer" ]]
    then (( a &lt; b ))
  else
    [[ $a &lt; $b ]]
  fi

then
  echo '$a меньше $b'
fi
</pre>
                <br>
                <br>

                <p><span class="emphasis"><em class="EMPHASIS">Это детальное описание конструкции
                <span class="QUOTE">"if-test"</span> любезно
                предоставлено Stephane Chazelas.</em></span></p>
              </li>
            </ul>

            <div class="EXAMPLE">
              <a name="EX10"></a>

              <p><strong>Пример 7-1. Что есть
              "истина"?</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

echo

echo "Проверяется \"0\""
if [ 0 ]      # ноль
then
  echo "0 -- это истина."
else
  echo "0 -- это ложь."
fi            # 0 -- это истина.

echo

echo "Проверяется \"1\""
if [ 1 ]      # единица
then
  echo "1 -- это истина."
else
  echo "1 -- это ложь."
fi            # 1 -- это ложь.

echo

echo "Testing \"-1\""
if [ -1 ]     # минус один
then
  echo "-1 -- это истина."
else
  echo "-1 -- это ложь."
fi            # -1 -- это истина.

echo

echo "Проверяется \"NULL\""
if [ ]        # NULL (пустое условие)
then
  echo "NULL -- это истина."
else
  echo "NULL -- это ложь."
fi            # NULL -- это ложь.

echo

echo "Проверяется \"xyz\""
if [ xyz ]    # строка
then
  echo "Случайная строка -- это истина."
else
  echo "Случайная строка -- это ложь."
fi            # Случайная строка -- это истина.

echo

echo "Проверяется \"\$xyz\""
if [ $xyz ]   # Проверка, если $xyz это null, но...
              # только для неинициализированных переменных.
then
  echo "Неинициализированная переменная -- это истина."
else
  echo "Неинициализированная переменная -- это ложь."
fi            # Неинициализированная переменная -- это ложь.

echo

echo "Проверяется \"-n \$xyz\""
if [ -n "$xyz" ]            # Более корректный вариант.
then
  echo "Неинициализированная переменная -- это истина."
else
  echo "Неинициализированная переменная -- это ложь."
fi            # Неинициализированная переменная -- это ложь.

echo


xyz=          # Инициализирована пустым значением.

echo "Проверяется \"-n \$xyz\""
if [ -n "$xyz" ]
then
  echo "Пустая переменная -- это истина."
else
  echo "Пустая переменная -- это ложь."
fi            # Пустая переменная -- это ложь.


echo


# Кргда "ложь" истинна?

echo "Проверяется \"false\""
if [ "false" ]              #  это обычная строка "false".
then
  echo "\"false\" -- это истина." #+ и она истинна.
else
  echo "\"false\" -- это ложь."
fi            # "false" -- это истина.

echo

echo "Проверяется \"\$false\""  # Опять неинициализированная переменная.
if [ "$false" ]
then
  echo "\"\$false\" -- это истина."
else
  echo "\"\$false\" -- это ложь."
fi            # "$false" -- это ложь.
              # Теперь мв получили ожидаемый результат.


echo

exit 0
</pre>
            </div>

            <div class="FORMALPARA">
              <p><strong>Упражнение.</strong> Объясните результаты,
              полученные в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX10">Пример 7-1</a>.</p>
            </div>
<pre class="PROGRAMLISTING">if [ condition-true ]
then
   command 1
   command 2
   ...
else
   # Необязательная ветка (можно опустить, если в ней нет необходимости).
   # Дополнительный блок кода,
   # исполняемый в случае, когда результат проверки -- "ложь".
   command 3
   command 4
   ...
fi
</pre>
            <br>
            <br>

            <div class="NOTE">
              <table class="NOTE" width="100%" border="0">
                <tbody><tr>
                  <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                  <td align="left" valign="top">
                    <p>Когда <span class="emphasis"><em class="EMPHASIS">if</em></span> и <span class="emphasis"><em class="EMPHASIS">then</em></span> располагаются в
                    одной строке, то конструкция <span class="emphasis"><em class="EMPHASIS">if</em></span> должна завершаться
                    точкой с запятой. И <span class="emphasis"><em class="EMPHASIS">if</em></span>, и <span class="emphasis"><em class="EMPHASIS">then</em></span> -- это <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#KEYWORDREF">зарезервированные слова</a>.
                    Зарезервированные слова начинают инструкцию,
                    которая должна быть завершена прежде, чем в той же
                    строке появится новая инструкция.</p>
<pre class="PROGRAMLISTING">if [ -x "$filename" ]; then
</pre>
                    <br>
                    <br>
                  </td>
                </tr>
              </tbody></table>
            </div>

            <div class="VARIABLELIST">
              <p><strong><a name="ELIFREF1"></a>Else if и elif</strong></p>

              <dl>
                <dt><span class="TOKEN">elif</span></dt>

                <dd>
                  <p><code class="USERINPUT"><strong>elif</strong></code> -- это
                  краткая форма записи конструкции <span class="TOKEN">else if</span>. Применяется для
                  построения многоярусных инструкций <span class="TOKEN">if/then</span>.</p>
<pre class="PROGRAMLISTING">if [ condition1 ]
then
   command1
   command2
   command3
elif [ condition2 ]
# То же самое, что и else if
then
   command4
   command5
else
   default-command
fi
</pre>
                  <br>
                  <br>
                </dd>
              </dl>
            </div>

            <p>Конструкция <code class="USERINPUT"><strong>if test
            condition-true</strong></code> является точным эквивалентом
            конструкции <code class="USERINPUT"><strong>if [ condition-true
            ]</strong></code>, где левая квадратная скобка <strong class="COMMAND">[</strong> выполняет те же действия, что и
            команда <strong class="COMMAND">test</strong>. Закрывающая правая
            квадратная скобка <strong class="COMMAND">]</strong> не является абсолютно
            необходимой, однако, более новые версии Bash требуют ее
            наличие.</p>

            <div class="NOTE">
              <table class="NOTE" width="100%" border="0">
                <tbody><tr>
                  <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                  <td align="left" valign="top">
                    <p>Команда <strong class="COMMAND">test</strong> -- это <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BUILTINREF">встроенная</a> команда Bash,
                    которая выполняет проверки файлов и производит
                    сравнение строк. Таким образом, в Bash-скриптах,
                    команда <strong class="COMMAND">test</strong> <span class="emphasis"><em class="EMPHASIS">не</em></span> вызывает внешнюю
                    (<code class="FILENAME">/usr/bin/test</code>) утилиту,
                    которая является частью пакета <span class="emphasis"><em class="EMPHASIS">sh-utils</em></span>. Аналогично,
                    <span class="TOKEN">[</span> не производит вызов утилиты
                    <code class="FILENAME">/usr/bin/[</code>, которая является
                    символической ссылкой на <code class="FILENAME">/usr/bin/test</code>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>type test</strong></code>
<code class="COMPUTEROUTPUT">test is a shell builtin</code>
<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>type '['</strong></code>
<code class="COMPUTEROUTPUT">[ is a shell builtin</code>
<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>type '[['</strong></code>
<code class="COMPUTEROUTPUT">[[ is a shell keyword</code>
<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>type ']]'</strong></code>
<code class="COMPUTEROUTPUT">]] is a shell keyword</code>
<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>type ']'</strong></code>
<code class="COMPUTEROUTPUT">bash: type: ]: not found</code>
             
</pre>
                    <br>
                    <br>
                  </td>
                </tr>
              </tbody></table>
            </div>

            <div class="EXAMPLE">
              <a name="EX11"></a>

              <p><strong>Пример 7-2. Эквиваленты команды <span class="TOKEN">test</span> -- <code class="FILENAME">/usr/bin/test</code>, <span class="TOKEN">[ ]</span>, и <code class="FILENAME">/usr/bin/[</code></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

echo

if test -z "$1"
then
  echo "Аргументы командной строки отсутствуют."
else
  echo "Первый аргумент командной строки: $1."
fi

echo

if /usr/bin/test -z "$1"      # Дает тот же рузультат, что и встроенная команда "test".
then
  echo "Аргументы командной строки отсутствуют."
else
  echo "Первый аргумент командной строки: $1."
fi

echo

if [ -z "$1" ]                # Функционально идентично вышеприведенному блоку кода.
#   if [ -z "$1"                эта конструкция должна работать, но...
#+  Bash выдает сообщение об отсутствующей закрывающей скобке.
then
  echo "Аргументы командной строки отсутствуют."
else
  echo "Первый аргумент командной строки: $1."
fi

echo

if /usr/bin/[ -z "$1"         # Функционально идентично вышеприведенному блоку кода.
# if /usr/bin/[ -z "$1" ]     # Работает, но выдает сообщение об ошибке.
then
  echo "Аргументы командной строки отсутствуют."
else
  echo "Первый аргумент командной строки: $1."
fi

echo

exit 0
</pre>
            </div>

            <p><a name="DBLBRACKETS"></a>Конструкция <span class="TOKEN">[[ ]]</span> более универсальна, по
            сравнению с <span class="TOKEN">[ ]</span>. Этот <span class="emphasis"><em class="EMPHASIS">расширенный вариант команды
            test</em></span> перекочевал в Bash из <span class="emphasis"><em class="EMPHASIS">ksh88</em></span>.</p>

            <div class="NOTE">
              <table class="NOTE" width="100%" border="0">
                <tbody><tr>
                  <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                  <td align="left" valign="top">
                    <p>Внутри этой конструкции не производится никакой
                    дополнительной интерпретации имен файлов и не
                    производится разбиение аргументов на отдельные
                    слова, но допускается подстановка параметров и
                    команд.</p>
                  </td>
                </tr>
              </tbody></table>
            </div>
<pre class="PROGRAMLISTING">file=/etc/passwd

if [[ -e $file ]]
then
  echo "Файл паролей найден."
fi
</pre>
            <br>
            <br>

            <div class="TIP">
              <table class="TIP" width="100%" border="0">
                <tbody><tr>
                  <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/tip.gif" hspace="5" alt="Tip"></td>

                  <td align="left" valign="top">
                    <p>Конструкция <strong class="COMMAND">[[ ... ]]</strong> более
                    предпочтительна, нежели <strong class="COMMAND">[ ... ]</strong>, поскольку
                    поможет избежать некоторых логических ошибок.
                    Например, операторы <span class="TOKEN">&amp;&amp;</span>, <span class="TOKEN">||</span>, <span class="TOKEN">&lt;</span> и <span class="TOKEN">&gt;</span> внутри <span class="TOKEN">[[ ]]</span> вполне допустимы, в то
                    время как внутри <span class="TOKEN">[ ]</span> порождают сообщения об
                    ошибках.</p>
                  </td>
                </tr>
              </tbody></table>
            </div>

            <div class="NOTE">
              <table class="NOTE" width="100%" border="0">
                <tbody><tr>
                  <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                  <td align="left" valign="top">
                    <p>Строго говоря, после оператора <strong class="COMMAND">if</strong>, ни команда <strong class="COMMAND">test</strong>, ни квадратные
                    скобки ( [ ] или [[ ]] ) не являются
                    обязательными.</p>
<pre class="PROGRAMLISTING">dir=/home/bozo

if cd "$dir" 2&gt;/dev/null; then   # "2&gt;/dev/null" подавление вывода сообщений об ошибках.
  echo "Переход в каталог $dir выполнен."
else
  echo "Невозможно перейти в каталог $dir."
fi
</pre>
                    Инструкция "if COMMAND" возвращает код
                    возврата команды COMMAND.<br>
                    <br>

                    <p>Точно так же, условие, находящееся внутри
                    квадратных скобок может быть проверено без
                    использования оператора <strong class="COMMAND">if</strong>.</p>
<pre class="PROGRAMLISTING">var1=20
var2=22
[ "$var1" -ne "$var2" ] &amp;&amp; echo "$var1 не равно $var2"

home=/home/bozo
[ -d "$home" ] || echo "каталог $home не найден."
</pre>
                    <br>
                    <br>
                  </td>
                </tr>
              </tbody></table>
            </div>

            <p>Внутри <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DBLPARENS">(( ))</a> производится вычисление
            арифметического выражения. Если результатом вычислений
            является ноль, то возвращается <span class="RETURNVALUE">1</span>, или <span class="QUOTE">"ложь"</span>. Ненулевой результат
            дает код возврата <span class="RETURNVALUE">0</span>, или <span class="QUOTE">"истина"</span>. То есть полная
            противоположность инструкциям <strong class="COMMAND">test</strong> и <span class="TOKEN">[ ]</span>, обсуждавшимся выше.</p>

            <div class="EXAMPLE">
              <a name="ARITHTESTS"></a>

              <p><strong>Пример 7-3. Арифметические выражения внутри
              <span class="TOKEN">(( ))</span></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Проверка арифметических выражений.

# Инструкция (( ... )) вычисляет арифметические выражения.
# Код возврата противоположен коду возврата инструкции [ ... ] !

(( 0 ))
echo "Код возврата \"(( 0 ))\":  $?."         # 1

(( 1 ))
echo "Код возврата \"(( 1 ))\":  $?."         # 0

(( 5 &gt; 4 ))                                   # true
echo "Код возврата \"(( 5 &gt; 4 ))\":  $?."     # 0

(( 5 &gt; 9 ))                                   # false
echo "Код возврата \"(( 5 &gt; 9 ))\":  $?."     # 1

(( 5 - 5 ))                                   # 0
echo "Код возврата \"(( 5 - 5 ))\":  $?."     # 1

(( 5 / 4 ))                                   # Деление, все в порядке
echo "Код возврата \"(( 5 / 4 ))\":  $?."     # 0

(( 1 / 2 ))                                   # Результат деления &lt; 1.
echo "Код возврата \"(( 1 / 2 ))\":  $?."     # Округляется до 0.
                                              # 1

(( 1 / 0 )) 2&gt;/dev/null                       # Деление на 0.
echo "Код возврата \"(( 1 / 0 ))\":  $?."     # 1

# Для чего нужна инструкция "2&gt;/dev/null" ?
# Что произойдет, если ее убрать?
# Попробуйте убрать ее и выполнить сценарий.

exit 0
</pre>
            </div>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="FTO"></a>7.2. Операции проверки файлов</h2>

            <div class="VARIABLELIST">
              <p><strong><a name="RTIF"></a>Возвращает true если...</strong></p>

              <dl>
                <dt><span class="TOKEN">-e</span></dt>

                <dd>
                  <p>файл существует</p>
                </dd>

                <dt><span class="TOKEN">-f</span></dt>

                <dd>
                  <p><code class="REPLACEABLE"><em>обычный</em></code> файл (не
                  каталог и не файл устройства)</p>
                </dd>

                <dt><span class="TOKEN">-s</span></dt>

                <dd>
                  <p>ненулевой размер файла</p>
                </dd>

                <dt><span class="TOKEN">-d</span></dt>

                <dd>
                  <p>файл является каталогом</p>
                </dd>

                <dt><span class="TOKEN">-b</span></dt>

                <dd>
                  <p>файл является блочным устройством (floppy, cdrom и
                  т.п.)</p>
                </dd>

                <dt><span class="TOKEN">-c</span></dt>

                <dd>
                  <p>файл является символьным устройством (клавиатура,
                  модем, звуковая карта и т.п.)</p>
                </dd>

                <dt><span class="TOKEN">-p</span></dt>

                <dd>
                  <p>файл является каналом</p>
                </dd>

                <dt><span class="TOKEN">-h</span></dt>

                <dd>
                  <p>файл является символической ссылкой</p>
                </dd>

                <dt><span class="TOKEN">-L</span></dt>

                <dd>
                  <p>файл является символической ссылкой</p>
                </dd>

                <dt><span class="TOKEN">-S</span></dt>

                <dd>
                  <p>файл является сокетом</p>
                </dd>

                <dt><span class="TOKEN">-t</span></dt>

                <dd>
                  <p>файл (<a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FDREF">дескриптор</a>) связан с терминальным
                  устройством</p>

                  <p>Этот ключ может использоваться для проверки --
                  является ли файл стандартным устройством ввода <code class="FILENAME">stdin</code> (<code class="USERINPUT"><strong>[ -t 0 ]</strong></code>)
                  или стандартным устройством вывода <code class="FILENAME">stdout</code> (<code class="USERINPUT"><strong>[ -t 1
                  ]</strong></code>).</p>
                </dd>

                <dt><span class="TOKEN">-r</span></dt>

                <dd>
                  <p>файл доступен для чтения (<span class="emphasis"><em class="EMPHASIS">пользователю, запустившему
                  сценарий</em></span>)</p>
                </dd>

                <dt><span class="TOKEN">-w</span></dt>

                <dd>
                  <p>файл доступен для записи (пользователю,
                  запустившему сценарий)</p>
                </dd>

                <dt><span class="TOKEN">-x</span></dt>

                <dd>
                  <p>файл доступен для исполнения (пользователю,
                  запустившему сценарий)</p>
                </dd>

                <dt><span class="TOKEN">-g</span></dt>

                <dd>
                  <p>set-group-id (sgid) флаг для файла или каталога
                  установлен</p>

                  <p>Если для каталога установлен флаг <code class="REPLACEABLE"><em>sgid</em></code>, то файлы,
                  создаваемые в таком каталоге, наследуют идентификатор
                  группы каталога, который может не совпадать с
                  идентификатором группы, к которой принадлежит
                  пользователь, создавший файл. Это может быть полезно
                  для каталогов, в которых хранятся файлы,
                  общедоступные для группы пользователей.</p>
                </dd>

                <dt><span class="TOKEN">-u</span></dt>

                <dd>
                  <p>set-user-id (suid) флаг для файла установлен</p>

                  <p>Установленный флаг suid приводит к изменению
                  привилегий запущенного процесса на привилегии
                  владельца исполняемого файла. Исполняемые файлы,
                  владельцем которых является <span class="emphasis"><em class="EMPHASIS">root</em></span>, с установленным
                  флагом <code class="REPLACEABLE"><em>set-user-id</em></code>
                  запускаются с привилегиями <span class="emphasis"><em class="EMPHASIS">root</em></span>, даже если их
                  запускает обычный пользователь. <a name="AEN2488" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN2488"><span class="footnote">[16]</span></a> Это может оказаться
                  полезным для некоторых программ (таких как <strong class="COMMAND">pppd</strong> и <strong class="COMMAND">cdrecord</strong>), которые
                  осуществляют доступ к аппаратной части компьютера. В
                  случае отсутствия флага <span class="emphasis"><em class="EMPHASIS">suid</em></span>, программы не
                  смогут быть запущены рядовым пользователем, не
                  обладающим привилегиями root.</p>
<pre class="SCREEN">             <code class="COMPUTEROUTPUT">-rwsr-xr-t    1 root       178236 Oct  2  2000 /usr/sbin/pppd</code>
             
</pre>
                  Файл с установленным флагом <code class="REPLACEABLE"><em>suid</em></code> отображается
                  с включенным флагом <span class="emphasis"><em class="EMPHASIS">s</em></span> в поле прав
                  доступа.<br>
                  <br>
                </dd>

                <dt><span class="TOKEN">-k</span></dt>

                <dd>
                  <p>флаг <code class="REPLACEABLE"><em>sticky bit</em></code> (бит
                  фиксации) установлен</p>

                  <p>Общеизвестно, что флаг <span class="QUOTE">"sticky bit"</span> -- это
                  специальный тип прав доступа к файлам. Программы с
                  установленным флагом <span class="QUOTE">"sticky bit"</span> остаются
                  в системном кэше после своего завершения, обеспечивая
                  тем самым более быстрый запуск программы. <a name="AEN2508" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN2508"><span class="footnote">[17]</span></a> Если флаг
                  установлен для каталога, то это приводит к
                  ограничению прав на запись. Установленный флаг
                  "sticky bit" отображается в виде символа
                  <span class="emphasis"><em class="EMPHASIS">t</em></span> в поле прав
                  доступа.</p>
<pre class="SCREEN">             <code class="COMPUTEROUTPUT">drwxrwxrwt    7 root         1024 May 19 21:26 tmp/</code>
             
</pre>
                  Если пользователь не является владельцем каталога, с
                  установленным "sticky bit", но имеет право
                  на запись в каталог, то он может удалять только те
                  файлы в каталоге, владельцем которых он является. Это
                  предотвращает удаление и перезапись "чужих"
                  файлов в общедоступных каталогах, таких как <code class="FILENAME">/tmp</code>.<br>
                  <br>
                </dd>

                <dt><span class="TOKEN">-O</span></dt>

                <dd>
                  <p>вы являетесь владельцем файла</p>
                </dd>

                <dt><span class="TOKEN">-G</span></dt>

                <dd>
                  <p>вы принадлежите к той же группе, что и файл</p>
                </dd>

                <dt><span class="TOKEN">-N</span></dt>

                <dd>
                  <p>файл был модифицирован с момента последнего
                  чтения</p>
                </dd>

                <dt><span class="TOKEN">f1 -nt f2</span></dt>

                <dd>
                  <p>файл <code class="REPLACEABLE"><em>f1</em></code> более новый,
                  чем <code class="REPLACEABLE"><em>f2</em></code></p>
                </dd>

                <dt><span class="TOKEN">f1 -ot f2</span></dt>

                <dd>
                  <p>файл <code class="REPLACEABLE"><em>f1</em></code> более старый,
                  чем <code class="REPLACEABLE"><em>f2</em></code></p>
                </dd>

                <dt><span class="TOKEN">f1 -ef f2</span></dt>

                <dd>
                  <p>файлы <code class="REPLACEABLE"><em>f1</em></code> и <code class="REPLACEABLE"><em>f2</em></code> являются
                  "жесткими" ссылками на один и тот же
                  файл</p>
                </dd>

                <dt><span class="TOKEN">!</span></dt>

                <dd>
                  <p><span class="QUOTE">"НЕ"</span> -- логическое
                  отрицание (инверсия) результатов всех вышеприведенных
                  проверок (возвращается true если условие
                  отсутствует).</p>
                </dd>
              </dl>
            </div>

            <div class="EXAMPLE">
              <a name="BROKENLINK"></a>

              <p><strong>Пример 7-4. Проверка "битых"
              ссылок</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# broken-link.sh
# Автор Lee Bigelow &lt;ligelowbee@yahoo.com&gt;
# Используется с его разрешения.

#Сценарий поиска "битых" ссылок и их вывод в "окавыченном" виде
#таким образом они могут передаваться утилите xargs для дальнейшей обработки :)
#например. broken-link.sh /somedir /someotherdir|xargs rm
#
#На всякий случай приведу лучший метод:
#
#find "somedir" -type l -print0|\
#xargs -r0 file|\
#grep "broken symbolic"|
#sed -e 's/^\|: *broken symbolic.*$/"/g'
#
#но это не чисто BASH-евский метод, а теперь сам сценарий.
#Внимание! будьте осторожны с файловой системой /proc и циклическими ссылками!
##############################################################


#Если скрипт не получает входных аргументов,
#то каталогом поиска является текущая директория
#В противном случае, каталог поиска задается из командной строки
####################
[ $# -eq 0 ] &amp;&amp; directorys=`pwd` || directorys=$@

#Функция linkchk проверяет каталог поиска
#на наличие в нем ссылок на несуществующие файлы, и выводит их имена.
#Если анализируемый файл является каталогом,
#то он передается функции linkcheck рекурсивно.
##########
linkchk () {
    for element in $1/*; do
    [ -h "$element" -a ! -e "$element" ] &amp;&amp; echo \"$element\"
    [ -d "$element" ] &amp;&amp; linkchk $element
    # Само собой, '-h' проверяет символические ссылки, '-d' -- каталоги.
    done
}

#Вызов функции linkchk для каждого аргумента командной строки,
#если он является каталогом.  Иначе выводится сообщение об ошибке
#и информация о порядке пользования скриптом.
################
for directory in $directorys; do
    if [ -d $directory ]
        then linkchk $directory
        else
            echo "$directory не является каталогом"
            echo "Порядок использования: $0 dir1 dir2 ..."
    fi
done

exit 0
</pre>
            </div>

            <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COOKIES">Пример 28-1</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BINGREP">Пример 10-7</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FILEINFO">Пример 10-3</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RAMDISK">Пример 28-3</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MAILFORMAT">Пример A-2</a> так же иллюстрируют
            операции проверки файлов.</p>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="COMPARISON-OPS"></a>7.3. Операции сравнения</h2>

            <div class="VARIABLELIST">
              <p><strong><a name="ICOMPARISON1"></a>сравнение целых
              чисел</strong></p>

              <dl>
                <dt><span class="TOKEN">-eq</span></dt>

                <dd>
                  <p><a name="EQUALREF"></a></p>

                  <p>равно</p>

                  <p><code class="USERINPUT"><strong>if [ "$a" -eq
                  "$b" ]</strong></code></p>
                </dd>

                <dt><span class="TOKEN">-ne</span></dt>

                <dd>
                  <p>не равно</p>

                  <p><code class="USERINPUT"><strong>if [ "$a" -ne
                  "$b" ]</strong></code></p>
                </dd>

                <dt><span class="TOKEN">-gt</span></dt>

                <dd>
                  <p>больше</p>

                  <p><code class="USERINPUT"><strong>if [ "$a" -gt
                  "$b" ]</strong></code></p>
                </dd>

                <dt><span class="TOKEN">-ge</span></dt>

                <dd>
                  <p>больше или равно</p>

                  <p><code class="USERINPUT"><strong>if [ "$a" -ge
                  "$b" ]</strong></code></p>
                </dd>

                <dt><span class="TOKEN">-lt</span></dt>

                <dd>
                  <p>меньше</p>

                  <p><code class="USERINPUT"><strong>if [ "$a" -lt
                  "$b" ]</strong></code></p>
                </dd>

                <dt><span class="TOKEN">-le</span></dt>

                <dd>
                  <p>меньше или равно</p>

                  <p><code class="USERINPUT"><strong>if [ "$a" -le
                  "$b" ]</strong></code></p>
                </dd>

                <dt><a name="INTLT"></a><span class="TOKEN">&lt;</span></dt>

                <dd>
                  <p>меньше (внутри <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DBLPARENS">двойных круглых скобок</a> )</p>

                  <p><code class="USERINPUT"><strong>(("$a" &lt;
                  "$b"))</strong></code></p>
                </dd>

                <dt><span class="TOKEN">&lt;=</span></dt>

                <dd>
                  <p>меньше или равно (внутри двойных круглых
                  скобок)</p>

                  <p><code class="USERINPUT"><strong>(("$a" &lt;=
                  "$b"))</strong></code></p>
                </dd>

                <dt><span class="TOKEN">&gt;</span></dt>

                <dd>
                  <p>больше (внутри двойных круглых скобок)</p>

                  <p><code class="USERINPUT"><strong>(("$a" &gt;
                  "$b"))</strong></code></p>
                </dd>

                <dt><span class="TOKEN">&gt;=</span></dt>

                <dd>
                  <p>больше или равно (внутри двойных круглых
                  скобок)</p>

                  <p><code class="USERINPUT"><strong>(("$a" &gt;=
                  "$b"))</strong></code></p>
                </dd>
              </dl>
            </div>

            <div class="VARIABLELIST">
              <p><strong><a name="SCOMPARISON1"></a>сравнение строк</strong></p>

              <dl>
                <dt><span class="TOKEN">=</span></dt>

                <dd>
                  <p><a name="EQUALSIGNREF"></a></p>

                  <p>равно</p>

                  <p><code class="USERINPUT"><strong>if [ "$a" =
                  "$b" ]</strong></code></p>
                </dd>

                <dt><span class="TOKEN">==</span></dt>

                <dd>
                  <p>равно</p>

                  <p><code class="USERINPUT"><strong>if [ "$a" ==
                  "$b" ]</strong></code></p>

                  <p>Синоним оператора <span class="TOKEN">=</span>.</p>
<pre class="PROGRAMLISTING">[[ $a == z* ]]    # истина, если $a начинается с символа "z" (сравнение по шаблону)
[[ $a == "z*" ]]  # истина, если $a равна z*

[ $a == z* ]      # имеют место подстановка имен файлов и разбиение на слова
[ "$a" == "z*" ]  # истина, если $a равна z*

# Спасибо S.C.
</pre>
                  <br>
                  <br>
                </dd>

                <dt><span class="TOKEN">!=</span></dt>

                <dd>
                  <p>не равно</p>

                  <p><code class="USERINPUT"><strong>if [ "$a" !=
                  "$b" ]</strong></code></p>

                  <p>Этот оператор используется при поиске по шаблону
                  внутри <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DBLBRACKETS">[[ ... ]]</a>.</p>
                </dd>

                <dt><a name="LTREF"></a><span class="TOKEN">&lt;</span></dt>

                <dd>
                  <p>меньше, в смысле величины ASCII-кодов</p>

                  <p><code class="USERINPUT"><strong>if [[ "$a" &lt;
                  "$b" ]]</strong></code></p>

                  <p><code class="USERINPUT"><strong>if [ "$a" \&lt;
                  "$b" ]</strong></code></p>

                  <p>Обратите внимание! Символ <span class="QUOTE">"&lt;"</span> необходимо
                  экранировать внутри <code class="USERINPUT"><strong>[ ]</strong></code>.</p>
                </dd>

                <dt><a name="GTREF"></a><span class="TOKEN">&gt;</span></dt>

                <dd>
                  <p>больше, в смысле величины ASCII-кодов</p>

                  <p><code class="USERINPUT"><strong>if [[ "$a" &gt;
                  "$b" ]]</strong></code></p>

                  <p><code class="USERINPUT"><strong>if [ "$a" \&gt;
                  "$b" ]</strong></code></p>

                  <p>Обратите внимание! Символ <span class="QUOTE">"&gt;"</span> необходимо
                  экранировать внутри <code class="USERINPUT"><strong>[ ]</strong></code>.</p>

                  <p>См. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BUBBLE">Пример 25-6</a> относительно
                  применения этого оператора сравнения.</p>
                </dd>

                <dt><span class="TOKEN">-z</span></dt>

                <dd>
                  <p>строка <span class="QUOTE">"пустая"</span>, т.е. имеет
                  нулевую длину</p>
                </dd>

                <dt><span class="TOKEN">-n</span></dt>

                <dd>
                  <p>строка не <span class="QUOTE">"пустая"</span>.</p>

                  <div class="CAUTION">
                    <table class="CAUTION" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                        <td align="left" valign="top">
                          <p>Оператор <code class="USERINPUT"><strong>-n</strong></code>
                          требует, чтобы строка была заключена в
                          кавычки внутри квадратных скобок. Как
                          правило, проверка строк, не заключенных в
                          кавычки, оператором <code class="USERINPUT"><strong>!
                          -z</strong></code>, или просто указание строки
                          без кавычек внутри квадратных скобок (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#STRTEST">Пример 7-6</a>), проходит
                          нормально, однако это небезопасная, с точки
                          зрения отказоустойчивости, практика. <span class="emphasis"><em class="EMPHASIS">Всегда</em></span>
                          заключайте проверяемую строку в кавычки. <a name="AEN2722" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN2722"><span class="footnote">[18]</span></a></p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>
              </dl>
            </div>

            <div class="EXAMPLE">
              <a name="EX13"></a>

              <p><strong>Пример 7-5. Операции сравнения</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

a=4
b=5

#  Здесь переменные "a" и "b" могут быть как целыми числами, так и строками.
#  Здесь наблюдается некоторое размывание границ
#+ между целочисленными и строковыми переменными,
#+ поскольку переменные в Bash не имеют типов.

#  Bash выполняет целочисленные операции над теми переменными,
#+ которые содержат только цифры
#  Будьте внимательны!

echo

if [ "$a" -ne "$b" ]
then
  echo "$a не равно $b"
  echo "(целочисленное сравнение)"
fi

echo

if [ "$a" != "$b" ]
then
  echo "$a не равно $b."
  echo "(сравнение строк)"
  #     "4"  != "5"
  # ASCII 52 != ASCII 53
fi

# Оба варианта, "-ne" и "!=", работают правильно.

echo

exit 0
</pre>
            </div>

            <div class="EXAMPLE">
              <a name="STRTEST"></a>

              <p><strong>Пример 7-6. Проверка -- является ли строка
              <span class="emphasis"><em class="EMPHASIS">пустой</em></span></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# str-test.sh: Проверка пустых строк и строк, не заключенных в кавычки,

# Используется конструкция   if [ ... ]


# Если строка не инициализирована, то она не имеет никакого определенного значения.
# Такое состояние называется "null" (пустая) (это не то же самое, что ноль).

if [ -n $string1 ]    # $string1 не была объявлена или инициализирована.
then
  echo "Строка \"string1\" не пустая."
else
  echo "Строка \"string1\" пустая."
fi
# Неверный результат.
# Выводится сообщение о том, что $string1 не пустая,
#+не смотря на то, что она не была инициализирована.


echo


# Попробуем еще раз.

if [ -n "$string1" ]  # На этот раз, переменная $string1 заключена в кавычки.
then
  echo "Строка \"string1\" не пустая."
else
  echo "Строка \"string1\" пустая."
fi      # Внутри квадратных скобок заключайте строки в кавычки!


echo


if [ $string1 ]       # Опустим оператор -n.
then
  echo "Строка \"string1\" не пустая."
else
  echo "Строка \"string1\" пустая."
fi
# Все работает прекрасно.
# Квадратные скобки -- [ ], без посторонней помощи определяют, что строка пустая.
# Тем не менее, хорошим тоном считается заключать строки в кавычки ("$string1").
#
# Как указывает Stephane Chazelas,
#    if [ $string 1 ]   один аргумент "]"
#    if [ "$string 1" ]  два аргумента, пустая "$string1" и "]"



echo



string1=initialized

if [ $string1 ]       # Опять, попробуем строку без ничего.
then
  echo "Строка \"string1\" не пустая."
else
  echo "Строка \"string1\" пустая."
fi
# И снова получим верный результат.
# И опять-таки, лучше поместить строку в кавычки ("$string1"), поскольку...


string1="a = b"

if [ $string1 ]       # И снова, попробуем строку без ничего..
then
  echo "Строка \"string1\" не пустая."
else
  echo "Строка \"string1\" пустая."
fi
# Строка без кавычек дает неверный результат!

exit 0
# Спвсибо Florian Wisser, за предупреждение.
</pre>
            </div>

            <div class="EXAMPLE">
              <a name="EX14"></a>

              <p><strong>Пример 7-7. zmost</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

#Просмотр gz-файлов с помощью утилиты 'most'

NOARGS=65
NOTFOUND=66
NOTGZIP=67

if [ $# -eq 0 ] # то же, что и:  if [ -z "$1" ]
# $1 должен существовать, но может быть пустым:  zmost "" arg2 arg3
then
  echo "Порядок использования: `basename $0` filename" &gt;&amp;2
  # Сообщение об ошибке на stderr.
  exit $NOARGS
  # Код возврата 65 (код ошибки).
fi

filename=$1

if [ ! -f "$filename" ]   # Кавычки необходимы на тот случай, если имя файла содержит пробелы.
then
  echo "Файл $filename не найден!" &gt;&amp;2
  # Сообщение об ошибке на stderr.
  exit $NOTFOUND
fi

if [ ${filename##*.} != "gz" ]
# Квадратные скобки нужны для выполнения подстановки значения переменной
then
  echo "Файл $1 не является gz-файлом!"
  exit $NOTGZIP
fi

zcat $1 | most

# Используется утилита 'most' (очень похожа на 'less').
# Последние версии 'most' могут просматривать сжатые файлы.
# Можно вставить 'more' или 'less', если пожелаете.


exit $?   # Сценарий возвращает код возврата, полученный по конвейеру.
# На самом деле команда "exit $?" не является обязательной,
# так как работа скрипта завершится здесь в любом случае,
</pre>
            </div>

            <div class="VARIABLELIST">
              <p><strong><a name="CCOMPARISON1"></a>построение сложных условий
              проверки</strong></p>

              <dl>
                <dt><span class="TOKEN">-a</span></dt>

                <dd>
                  <p>логическое И (and)</p>

                  <p><code class="REPLACEABLE"><em>exp1 -a exp2</em></code>
                  возвращает true, если <span class="emphasis"><em class="EMPHASIS">оба</em></span> выражения, и exp1,
                  и exp2 истинны.</p>
                </dd>

                <dt><span class="TOKEN">-o</span></dt>

                <dd>
                  <p>логическое ИЛИ (or)</p>

                  <p><code class="REPLACEABLE"><em>exp1 -o exp2</em></code>
                  возвращает true, если хотябы одно из выражений, exp1
                  <span class="emphasis"><em class="EMPHASIS">или</em></span> exp2 истинно.</p>
                </dd>
              </dl>
            </div>

            <p>Они похожи на операторы Bash <strong class="COMMAND">&amp;&amp;</strong> и <strong class="COMMAND">||</strong>, употребляемые в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DBLBRACKETS">двойных квадратных скобках</a>.</p>
<pre class="PROGRAMLISTING">[[ condition1 &amp;&amp; condition2 ]]
</pre>
            Операторы <strong class="COMMAND">-o</strong> и <strong class="COMMAND">-a</strong> употребляются совместно с
            командой <strong class="COMMAND">test</strong> или внутри одинарных
            квадратных скобок. 
<pre class="PROGRAMLISTING">if [ "$exp1" -a "$exp2" ]
</pre>
            <br>
            <br>

            <p>Чтобы увидеть эти операторы в действии, смотрите <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ANDOR">Пример 8-3</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TWODIM">Пример 25-11</a>.</p>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="NESTEDIFTHEN"></a>7.4. Вложенные условные операторы
            if/then</h2>

            <p>Операторы проверки условий <strong class="COMMAND">if/then</strong> могут быть вложенными
            друг в друга. Конечный результат будет таким же как если бы
            результаты всех проверок были объединены оператором <strong class="COMMAND">&amp;&amp;</strong>.</p>
<pre class="PROGRAMLISTING">if [ condition1 ]
then
  if [ condition2 ]
  then
    do-something  # Только если оба условия "condition1" и "condition2" истинны.
  fi
fi
</pre>
            <br>
            <br>

            <p>См. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX79">Пример 34-4</a> -- пример использования
            вложенных операторов <code class="REPLACEABLE"><em>if/then</em></code>.</p>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="TESTTEST"></a>7.5. Проверка степени усвоения
            материала</h2>

            <p>Для запуска X-сервера может быть использован файл <code class="FILENAME">xinitrc</code>. Этот файл содержит
            некоторое число операторов <span class="emphasis"><em class="EMPHASIS">if/then</em></span>. Ниже приводится
            отрывок из этого файла.</p>
<pre class="PROGRAMLISTING">if [ -f $HOME/.Xclients ]; then
  exec $HOME/.Xclients
elif [ -f /etc/X11/xinit/Xclients ]; then
  exec /etc/X11/xinit/Xclients
else
     # failsafe settings.  Although we should never get here
     # (we provide fallbacks in Xclients as well) it can't hurt.
     xclock -geometry 100x100-5+5 &amp;
     xterm -geometry 80x50-50+150 &amp;
     if [ -f /usr/bin/netscape -a -f /usr/share/doc/HTML/index.html ]; then
             netscape /usr/share/doc/HTML/index.html &amp;
     fi
fi
</pre>
            <br>
            <br>

            <p>Объясните действия условных операторов в вышеприведенном
            отрывке, затем просмотрите файл <code class="FILENAME">/etc/X11/xinit/xinitrc</code> и
            проанализируйте его. Возможно вам придется обратиться к
            разделам, посвященным <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GREPREF">grep</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SEDREF">sed</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REGEXREF">регулярным выражениям</a>.</p>
          </div>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="OPERATIONS"></a>Глава 8. Операции и смежные темы</h1>

          <div class="SECT1">
            <h2 class="SECT1"><a name="OPS"></a>8.1. Операторы</h2>

            <div class="VARIABLELIST">
              <p><strong><a name="ASNOP1"></a>присваивание</strong></p>

              <dl>
                <dt><code class="REPLACEABLE"><em>variable
                assignment</em></code></dt>

                <dd>
                  <p>Инициализация переменной или изменение ее
                  значения</p>
                </dd>

                <dt>=</dt>

                <dd>
                  <p>Универсальный оператор присваивания, пригоден как
                  для сравнения целых чисел, так и для сравнения
                  строк.</p>
<pre class="PROGRAMLISTING">var=27
category=minerals  # Пробелы до и после оператора "=" -- недопустимы.
</pre>
                  <br>
                  <br>

                  <div class="CAUTION">
                    <table class="CAUTION" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                        <td align="left" valign="top">
                          <p>Пусть вас не смущает, что оператор
                          присваивания (<span class="QUOTE">"="</span>), по
                          своему внешнему виду, совпадает с оператором
                          сравнения (<a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EQUALSIGNREF">=</a>).</p>
<pre class="PROGRAMLISTING">#    Здесь знак "="  выступает в качестве оператора сравнения

if [ "$string1" = "$string2" ]
# if [ "X$string1" = "X$string2" ] более отказоустойчивый вариант,
# предохраняет от "сваливания" по ошибке в случае, когда одна из переменных пуста.
# (добавленные символы "X" компенсируют друг друга.)
then
   command
fi
</pre>
                          <br>
                          <br>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>
              </dl>
            </div>

            <div class="VARIABLELIST">
              <p><strong><a name="AROPS1"></a>арифметические операторы</strong></p>

              <dl>
                <dt><span class="TOKEN">+</span></dt>

                <dd>
                  <p>сложение</p>
                </dd>

                <dt><span class="TOKEN">-</span></dt>

                <dd>
                  <p>вычитание</p>
                </dd>

                <dt><span class="TOKEN">*</span></dt>

                <dd>
                  <p>умножение</p>
                </dd>

                <dt><span class="TOKEN">/</span></dt>

                <dd>
                  <p>деление</p>
                </dd>

                <dt><a name="EXPONENTIATIONREF"></a><span class="TOKEN">**</span></dt>

                <dd>
                  <p>возведение в степень</p>
<pre class="PROGRAMLISTING"># В Bash, начиная с версии 2.02, был введен оператор возведения в степень -- "**".

let "z=5**3"
echo "z = $z"   # z = 125
</pre>
                  <br>
                  <br>
                </dd>

                <dt><a name="MODULOREF"></a><span class="TOKEN">%</span></dt>

                <dd>
                  <p>модуль (деление по модулю), возвращает остаток от
                  деления</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo `expr 5 % 3`</strong></code>
<code class="COMPUTEROUTPUT">2</code>
             
</pre>
                  <br>
                  <br>

                  <p>Этот оператор может применяться в алгоритмах
                  генерации псевдослучайных чисел в заданном диапазоне
                  (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX21">Пример 9-23</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RANDOMTEST">Пример 9-25</a>), для
                  форматирования вывода на экран (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#QFUNCTION">Пример 25-10</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COLLATZ">Пример A-7</a>), и даже для
                  генерации простых чисел (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PRIMES">Пример A-18</a>). На удивление часто
                  операцию деления по модулю можно встретить в
                  различных численных алгоритмах.</p>

                  <div class="EXAMPLE">
                    <a name="GCD"></a>

                    <p><strong>Пример 8-1. Наибольший общий
                    делитель</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# gcd.sh: поиск наибольшего общего делителя
#         по алгоритму Эвклида

#  Под "наибольшим общим делителем" (нод) двух целых чисел
#+ понимается наибольшее целое число, которое делит оба делимых без остатка.

#  Алгоритм Эвклида выполняет последовательное деление.
#  В каждом цикле,
#+ делимое  &lt;---  делитель
#+ делитель &lt;---  остаток
#+ до тех пор, пока остаток не станет равным нулю (остаток = 0).
#+ The gcd = dividend, on the final pass.
#
#  Замечательное описание алгоритма Эвклида можно найти
#  на сайте Jim Loy, http://www.jimloy.com/number/euclids.htm.


# ------------------------------------------------------
# Проверка входных параметров
ARGS=2
E_BADARGS=65

if [ $# -ne "$ARGS" ]
then
  echo "Порядок использования: `basename $0` первое-число второе-число"
  exit $E_BADARGS
fi
# ------------------------------------------------------


gcd ()
{

                                 #  Начальное присваивание.
  dividend=$1                    #  В сущности, не имеет значения
  divisor=$2                     #+ какой из них больше.
                                 #  Почему?

  remainder=1                    #  Если переменные неинициализировать,
                                 #+ то работа сценария будет прервана по ошибке
                                 #+ в первом же цикле.

  until [ "$remainder" -eq 0 ]
  do
    let "remainder = $dividend % $divisor"
    dividend=$divisor            # Повторить цикл с новыми исходными данными
    divisor=$remainder
  done                           # алгоритм Эвклида

}                                # последнее $dividend и есть нод.


gcd $1 $2

echo; echo "НОД чисел $1 и $2 = $dividend"; echo


# Упражнение :
# --------
#  Вставьте дополнительную проверку входных аргументов,
#+ и предусмотрите завершение работы сценария с сообщением об ошибке, если
#+ входные аргументы не являются целыми числами.

exit 0
</pre>
                  </div>
                </dd>

                <dt><span class="TOKEN">+=</span></dt>

                <dd>
                  <p><span class="QUOTE">"плюс-равно"</span>
                  (увеличивает значение переменной на заданное
                  число)</p>

                  <p><code class="USERINPUT"><strong>let "var +=
                  5"</strong></code> значение переменной <code class="VARNAME">var</code> будет увеличено на <code class="LITERAL">5</code>.</p>
                </dd>

                <dt><span class="TOKEN">-=</span></dt>

                <dd>
                  <p><span class="QUOTE">"минус-равно"</span>
                  (уменьшение значения переменной на заданное
                  число)</p>
                </dd>

                <dt><span class="TOKEN">*=</span></dt>

                <dd>
                  <p><span class="QUOTE">"умножить-равно"</span>
                  (умножить значение переменной на заданное число,
                  результат записать в переменную)</p>

                  <p><code class="USERINPUT"><strong>let "var *=
                  4"</strong></code> значение переменной <code class="VARNAME">var</code> будет увеличено в <code class="LITERAL">4</code> раза.</p>
                </dd>

                <dt><span class="TOKEN">/=</span></dt>

                <dd>
                  <p><span class="QUOTE">"слэш-равно"</span>
                  (уменьшение значения переменной в заданное число
                  раз)</p>
                </dd>

                <dt><span class="TOKEN">%=</span></dt>

                <dd>
                  <p><span class="QUOTE">"процент-равно"</span>
                  (найти остаток от деления значения переменной на
                  заданное число, результат записать в переменную)</p>

                  <p><span class="emphasis"><em class="EMPHASIS">Арифметические операторы очень
                  часто используются совместно с командами <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXPRREF">expr</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LETREF">let</a>.</em></span></p>

                  <div class="EXAMPLE">
                    <a name="ARITHOPS"></a>

                    <p><strong>Пример 8-2. Арифметические
                    операции</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# От 1 до 6 пятью различными способами.

n=1; echo -n "$n "

let "n = $n + 1"   # let "n = n + 1"   тоже допустимо
echo -n "$n "

: $((n = $n + 1))
# оператор ":" обязателен, поскольку в противном случае, Bash будет
#+ интерпретировать выражение "$((n = $n + 1))" как команду.
echo -n "$n "

n=$(($n + 1))
echo -n "$n "

: $[ n = $n + 1 ]
# оператор ":" обязателен, поскольку в противном случае, Bash будет
#+ интерпретировать выражение "$[ n = $n + 1 ]" как команду.
# Не вызывает ошибки даже если "n" содержит строку.
echo -n "$n "

n=$[ $n + 1 ]
#  Не вызывает ошибки даже если "n" содержит строку.
#* Старайтесь избегать употребления такой конструкции,
#+ поскольку она уже давно устарела и не переносима.
echo -n "$n "; echo

# Спасибо Stephane Chazelas.

exit 0
</pre>
                  </div>
                </dd>
              </dl>
            </div>

            <div class="NOTE">
              <table class="NOTE" width="100%" border="0">
                <tbody><tr>
                  <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                  <td align="left" valign="top">
                    <p>Целые числа в Bash фактически являются знаковыми
                    <span class="emphasis"><em class="EMPHASIS">длинными</em></span> целыми
                    (32-бит), с диапазоном изменений от -2147483648 до
                    2147483647. Если в результате какой либо операции
                    эти пределы будут превышены, то результат получится
                    ошибочным.</p>
<pre class="PROGRAMLISTING">a=2147483646
echo "a = $a"      # a = 2147483646
let "a+=1"         # Увеличить "a" на 1.
echo "a = $a"      # a = 2147483647
let "a+=1"         # увеличить "a" еще раз, с выходом за границы диапазона.
echo "a = $a"      # a = -2147483648
                   #      ОШИБКА! (выход за границы диапазона)
</pre>
                    <br>
                    <br>
                  </td>
                </tr>
              </tbody></table>
            </div>

            <div class="CAUTION">
              <table class="CAUTION" width="100%" border="0">
                <tbody><tr>
                  <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                  <td align="left" valign="top">
                    <p>Bash ничего не знает о существовании чисел с
                    плавающей запятой. Такие числа, из-за наличия
                    символа десятичной точки, он воспринимает как
                    строки.</p>
<pre class="PROGRAMLISTING">a=1.5

let "b = $a + 1.3"  # Ошибка.
# t2.sh: let: b = 1.5 + 1.3: syntax error in expression (error token is ".5 + 1.3")

echo "b = $b"       # b=1
</pre>
                    Для работы с числами с плавающей запятой в
                    сценариях можно использовать утилиту-калькулятор <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BCREF">bc</a>.<br>
                    <br>
                  </td>
                </tr>
              </tbody></table>
            </div>

            <div class="FORMALPARA">
              <p><strong>битовые операции.</strong> Битовые операции
              очень редко используются в сценариях командного
              интерпретатора. Их главное назначение, на мой взгляд,
              установка и проверка некоторых значений, читаемых из
              портов ввода-вывода и сокетов. <span class="QUOTE">"Битовые операции"</span>
              гораздо более уместны в компилирующих языках
              программирования, таких как C и C++.</p>
            </div>

            <div class="VARIABLELIST">
              <p><strong><a name="BITWSOPS1"></a>битовые операции</strong></p>

              <dl>
                <dt><span class="TOKEN">&lt;&lt;</span></dt>

                <dd>
                  <p>сдвигает на 1 бит влево (умножение на <code class="LITERAL">2</code>)</p>
                </dd>

                <dt><span class="TOKEN">&lt;&lt;=</span></dt>

                <dd>
                  <p><span class="QUOTE">"сдвиг-влево-равно"</span></p>

                  <p><code class="USERINPUT"><strong>let "var &lt;&lt;=
                  2"</strong></code> значение переменной <code class="VARNAME">var</code> сдвигается влево на 2 бита
                  (умножается на <code class="LITERAL">4</code>)</p>
                </dd>

                <dt><span class="TOKEN">&gt;&gt;</span></dt>

                <dd>
                  <p>сдвиг вправо на 1 бит (деление на <code class="LITERAL">2</code>)</p>
                </dd>

                <dt><span class="TOKEN">&gt;&gt;=</span></dt>

                <dd>
                  <p><span class="QUOTE">"сдвиг-вправо-равно"</span>
                  (имеет смысл обратный <span class="TOKEN">&lt;&lt;=</span>)</p>
                </dd>

                <dt><span class="TOKEN">&amp;</span></dt>

                <dd>
                  <p>по-битовое И (AND)</p>
                </dd>

                <dt><span class="TOKEN">&amp;=</span></dt>

                <dd>
                  <p><span class="QUOTE">"по-битовое
                  И-равно"</span></p>
                </dd>

                <dt><span class="TOKEN">|</span></dt>

                <dd>
                  <p>по-битовое ИЛИ (OR)</p>
                </dd>

                <dt><span class="TOKEN">|=</span></dt>

                <dd>
                  <p><span class="QUOTE">"по-битовое
                  ИЛИ-равно"</span></p>
                </dd>

                <dt><span class="TOKEN">~</span></dt>

                <dd>
                  <p>по-битовая инверсия</p>
                </dd>

                <dt><span class="TOKEN">!</span></dt>

                <dd>
                  <p>По-битовое отрицание</p>
                </dd>

                <dt><span class="TOKEN">^</span></dt>

                <dd>
                  <p>по-битовое ИСКЛЮЧАЮЩЕЕ ИЛИ (XOR)</p>
                </dd>

                <dt><span class="TOKEN">^=</span></dt>

                <dd>
                  <p><span class="QUOTE">"по-битовое
                  ИСКЛЮЧАЮЩЕЕ-ИЛИ-равно"</span></p>
                </dd>
              </dl>
            </div>

            <div class="VARIABLELIST">
              <p><strong><a name="LOGOPS1"></a>логические операции</strong></p>

              <dl>
                <dt><span class="TOKEN">&amp;&amp;</span></dt>

                <dd>
                  <p>логическое И (and)</p>
<pre class="PROGRAMLISTING">if [ $condition1 ] &amp;&amp; [ $condition2 ]
# То же самое, что:  if [ $condition1 -a $condition2 ]
# Возвращает true если оба операнда condition1 и condition2 истинны...

if [[ $condition1 &amp;&amp; $condition2 ]]    # То же верно
# Обратите внимание: оператор &amp;&amp; не должен использоваться внутри [ ... ].
</pre>
                  <br>
                  <br>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p>оператор <span class="TOKEN">&amp;&amp;</span>, в
                          зависимости от контекста, может так же
                          использоваться в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LISTCONSREF">И-списках</a> для
                          построения составных команд.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><a name="ORREF"></a><span class="TOKEN">||</span></dt>

                <dd>
                  <p>логическое ИЛИ (or)</p>
<pre class="PROGRAMLISTING">if [ $condition1 ] || [ $condition2 ]
# То же самое, что:  if [ $condition1 -o $condition2 ]
# Возвращает true если хотя бы один из операндов истинен...

if [[ $condition1 || $condition2 ]]    # Also works.
# Обратите внимание: оператор || не должен использоваться внутри [ ... ].
</pre>
                  <br>
                  <br>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p>Bash производит проверку <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXITSTATUSREF">кода возврата</a>
                          КАЖДОГО из операндов в логических
                          выражениях.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>

                  <div class="EXAMPLE">
                    <a name="ANDOR"></a>

                    <p><strong>Пример 8-3. Построение сложных условий,
                    использующих &amp;&amp; и ||</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

a=24
b=47

if [ "$a" -eq 24 ] &amp;&amp; [ "$b" -eq 47 ]
then
  echo "Первая проверка прошла успешно."
else
  echo "Первая проверка не прошла."
fi

# ОКА:  if [ "$a" -eq 24 &amp;&amp; "$b" -eq 47 ]
#          пытается выполнить  ' [ "$a" -eq 24 '
#          и терпит неудачу наткнувшись на ']'.
#
#    if [[ $a -eq 24 &amp;&amp; $b -eq 24 ]]   это правильный вариант
#    (в строке 17 оператор "&amp;&amp;" имеет иной смысл, нежели в строке 6.)
#    Спасибо Stephane Chazelas.


if [ "$a" -eq 98 ] || [ "$b" -eq 47 ]
then
  echo "Вторая проверка прошла успешно."
else
  echo "Вторая проверка не прошла."
fi


#  Опции -a и -o предоставляют
#+ альтернативный механизм проверки условий.
#  Спасибо Patrick Callahan.


if [ "$a" -eq 24 -a "$b" -eq 47 ]
then
  echo "Третья проверка прошла успешно."
else
  echo "Третья проверка не прошла."
fi


if [ "$a" -eq 98 -o "$b" -eq 47 ]
then
  echo "Четвертая проверка прошла успешно."
else
  echo "Четвертая проверка не прошла."
fi


a=rhino
b=crocodile
if [ "$a" = rhino ] &amp;&amp; [ "$b" = crocodile ]
then
  echo "Пятая проверка прошла успешно."
else
  echo "Пятая проверка не прошла."
fi

exit 0
</pre>
                  </div>

                  <p>Операторы <span class="TOKEN">&amp;&amp;</span> и <span class="TOKEN">||</span> могут использоваться и в
                  арифметических вычислениях.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo $(( 1 &amp;&amp; 2 )) $((3 &amp;&amp; 0)) $((4 || 0)) $((0 || 0))</strong></code>
<code class="COMPUTEROUTPUT">1 0 1 0</code>
             
</pre>
                  <br>
                  <br>
                </dd>
              </dl>
            </div>

            <div class="VARIABLELIST">
              <p><strong><a name="MISCOP1"></a>прочие операции</strong></p>

              <dl>
                <dt><a name="COMMAOP"></a><span class="TOKEN">,</span></dt>

                <dd>
                  <p>запятая</p>

                  <p>С помощью оператора <strong class="COMMAND">запятая</strong> можно связать
                  несколько арифметических в одну последовательность.
                  При разборе таких последовательностей, командный
                  интерпретатор вычисляет все выражения (которые могут
                  иметь побочные эффекты) в последовательности и
                  возвращает результат последнего.</p>
<pre class="PROGRAMLISTING">let "t1 = ((5 + 3, 7 - 1, 15 - 4))"
echo "t1 = $t1"               # t1 = 11

let "t2 = ((a = 9, 15 / 3))"  #  Выполняется присваивание "a" = 9,
                              #+ а затем вычисляется "t2".
echo "t2 = $t2    a = $a"     # t2 = 5    a = 9
</pre>
                  <br>
                  <br>

                  <p>Оператор запятая чаще всего находит применение в
                  <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FORLOOPREF1">циклах for</a>. См. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FORLOOPC">Пример 10-12</a>.</p>
                </dd>
              </dl>
            </div>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="NUMERICAL-CONSTANTS"></a>8.2. Числовые
            константы</h2>

            <p><a name="NUMCONSTANTS"></a>Интерпретатор командной оболочки
            воспринимает числа как десятичные, в противном случае числу
            должен предшествовать специальный префикс, либо число
            должно быть записано в особой нотации. Числа, начинающиеся
            с символа <code class="REPLACEABLE"><em>0</em></code>, считаются <code class="REPLACEABLE"><em>восьмеричными</em></code>. если
            числу предшествует префикс <code class="REPLACEABLE"><em>0x</em></code>, то число считается
            <code class="REPLACEABLE"><em>шестнадцатиричным</em></code>.
            Число, в записи которого присутствует символ <code class="REPLACEABLE"><em>#</em></code>, расценивается как
            запись числа с указанием основы счисления в виде <code class="REPLACEABLE"><em>ОСНОВА#ЧИСЛО</em></code>.</p>

            <div class="EXAMPLE">
              <a name="NUMBERS"></a>

              <p><strong>Пример 8-4. Различные представления числовых
              констант</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# numbers.sh: Различные представления числовых констант.

# Десятичное: по-умолчанию
let "dec = 32"
echo "десятичное число = $dec"             # 32
# Вобщем-то ничего необычного.


# Восьмеричное: числа начинаются с '0' (нуля)
let "oct = 032"
echo "восьмеричное число = $oct"           # 26
# Результат печатается в десятичном виде.
# --------- ------ -- -------

# Шестнадцатиричное: числа начинаются с '0x' или '0X'
let "hex = 0x32"
echo "шестнадцатиричное число = $hex"      # 50
# Результат печатается в десятичном виде.

# Другие основы счисления: ОСНОВА#ЧИСЛО
# ОСНОВА должна быть между 2 и 64.
# для записи ЧИСЛА должен использоваться соответствующий ОСНОВЕ диапазон символов,
# см. ниже.

let "bin = 2#111100111001101"
echo "двоичное число = $bin"               # 31181

let "b32 = 32#77"
echo "32-ричное число = $b32"              # 231

let "b64 = 64#@_"
echo "64-ричное число = $b64"              # 4094
#
#  Нотация ОСНОВА#ЧИСЛО может использоваться на ограниченном
#+ диапазоне основ счисления (от 2 до 64)
#  10 цифр + 26 символов в нижнем регистре + 26 символов в верхнем регистре + @ + _

echo

echo $((36#zz)) $((2#10101010)) $((16#AF16)) $((53#1aA))
                                         # 1295 170 44822 3375


#  Важное замечание:
#  --------------
#  Использование символов, для записи числа, выходящих за диапазо,
#+ соответствующий ОСНОВЕ счисления
#+ будет приводить к появлению сообщений об ошибках.

let "bad_oct = 081"
# numbers.sh: let: oct = 081: value too great for base (error token is "081")
#                  Для записи восьмеричных чисел допускается использовать
#+                 только цифры в диапазоне 0 - 7.

exit 0       # Спасибо Rich Bartell и Stephane Chazelas, за разъяснения.
</pre>
            </div>
          </div>
        </div>
      </div>

      <div class="PART">
        <a name="PART3"></a>

        <div class="TITLEPAGE">
          <h1 class="TITLE">Часть 3. Углубленный материал</h1>

          <div class="TOC">
            <dl>
              <dt><strong>Содержание</strong></dt>

              <dt>9. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#VARIABLES2">К вопросу о переменных</a></dt>

              <dd>
                <dl>
                  <dt>9.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#INTERNALVARIABLES">Внутренние
                  переменные</a></dt>

                  <dt>9.2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#STRING-MANIPULATION">Работа со
                  строками</a></dt>

                  <dd>
                    <dl>
                      <dt>9.2.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AWKSTRINGMANIP">Использование awk при
                      работе со строками</a></dt>

                      <dt>9.2.2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#STRFDISC">Дальнейшее обсуждение</a></dt>
                    </dl>
                  </dd>

                  <dt>9.3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PARAMETER-SUBSTITUTION">Подстановка
                  параметров</a></dt>

                  <dt>9.4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DECLAREREF">Объявление переменных: <strong class="COMMAND">declare</strong> и <strong class="COMMAND">typeset</strong></a></dt>

                  <dt>9.5. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IVR">Косвенные ссылки на переменные</a></dt>

                  <dt>9.6. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RANDOMVAR">$RANDOM: генерация псевдослучайных
                  целых чисел</a></dt>

                  <dt>9.7. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DBLPARENS">Двойные круглые скобки</a></dt>
                </dl>
              </dd>

              <dt>10. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LOOPS">Циклы и ветвления</a></dt>

              <dd>
                <dl>
                  <dt>10.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LOOPS1">Циклы</a></dt>

                  <dt>10.2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#NESTEDLOOPS">Вложенные циклы</a></dt>

                  <dt>10.3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LOOPCONTROL">Управление ходом выполнения
                  цикла</a></dt>

                  <dt>10.4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TESTBRANCH">Операторы выбора</a></dt>
                </dl>
              </dd>

              <dt>11. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#INTERNAL">Внутренние команды</a></dt>

              <dd>
                <dl>
                  <dt>11.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN6110">Команды управления
                  заданиями</a></dt>
                </dl>
              </dd>

              <dt>12. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXTERNAL">Внешние команды, программы и
              утилиты</a></dt>

              <dd>
                <dl>
                  <dt>12.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BASIC">Базовые команды</a></dt>

                  <dt>12.2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MOREADV">Более сложные команды</a></dt>

                  <dt>12.3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TIMEDATE">Команды для работы с датой и
                  временем</a></dt>

                  <dt>12.4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TEXTPROC">Команды обработки текста</a></dt>

                  <dt>12.5. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FILEARCHIV">Команды для работы с файлами и
                  архивами</a></dt>

                  <dt>12.6. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COMMUNICATIONS">Команды для работы с
                  сетью</a></dt>

                  <dt>12.7. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TERMINALCCMDS">Команды управления
                  терминалом</a></dt>

                  <dt>12.8. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MATHC">Команды выполнения математических
                  операций</a></dt>

                  <dt>12.9. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXTMISC">Прочие команды</a></dt>
                </dl>
              </dd>

              <dt>13. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SYSTEM">Команды системного
              администрирования</a></dt>

              <dt>14. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COMMANDSUB">Подстановка команд</a></dt>

              <dt>15. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ARITHEXP">Арифметические подстановки</a></dt>

              <dt>16. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IO-REDIRECTION">Перенаправление
              ввода/вывода</a></dt>

              <dd>
                <dl>
                  <dt>16.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN11702">С помощью команды <strong class="COMMAND">exec</strong></a></dt>

                  <dt>16.2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REDIRCB">Перенаправление для блоков
                  кода</a></dt>

                  <dt>16.3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REDIRAPPS">Область применения</a></dt>
                </dl>
              </dd>

              <dt>17. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#HERE-DOCS">Встроенные документы</a></dt>
            </dl>
          </div>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="VARIABLES2"></a>Глава 9. К вопросу о переменных</h1>

          <p>Правильное использование переменных может придать
          сценариям дополнительную мощь и гибкость, а для этого
          необходимо изучить все тонкости и нюансы.</p>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="INTERNALVARIABLES"></a>9.1. Внутренние
            переменные</h2>

            <div class="VARIABLELIST">
              <dl>
                <dt><code class="REPLACEABLE"><em><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BUILTINREF">Встроенные</a>
                переменные</em></code></dt>

                <dt><code class="VARNAME">$BASH</code></dt>

                <dd>
                  <p>путь к исполняемому файлу <span class="emphasis"><em class="EMPHASIS">Bash</em></span></p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo $BASH</strong></code>
<code class="COMPUTEROUTPUT">/bin/bash</code>
</pre>
                  <br>
                  <br>
                </dd>

                <dt><code class="VARNAME">$BASH_VERSINFO[n]</code></dt>

                <dd>
                  <p>это <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ARRAYREF">массив</a>, состоящий из 6
                  элементов, и содержащий информацию о версии Bash.
                  Очень похожа на переменную <code class="VARNAME">$BASH_VERSION</code>, описываемую
                  ниже.</p>
<pre class="PROGRAMLISTING"># Информация о версии Bash:

for n in 0 1 2 3 4 5
do
  echo "BASH_VERSINFO[$n] = ${BASH_VERSINFO[$n]}"
done

# BASH_VERSINFO[0] = 2                      # Major version no.
# BASH_VERSINFO[1] = 05                     # Minor version no.
# BASH_VERSINFO[2] = 8                      # Patch level.
# BASH_VERSINFO[3] = 1                      # Build version.
# BASH_VERSINFO[4] = release                # Release status.
# BASH_VERSINFO[5] = i386-redhat-linux-gnu  # Architecture
                                            # (same as $MACHTYPE).
</pre>
                  <br>
                  <br>
                </dd>

                <dt><code class="VARNAME">$BASH_VERSION</code></dt>

                <dd>
                  <p>версия Bash, установленного в системе</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo $BASH_VERSION</strong></code>
<code class="COMPUTEROUTPUT">2.04.12(1)-release</code>
             
</pre>
                  <br>
                  <br>
<pre class="SCREEN"><code class="PROMPT">tcsh%</code> <code class="USERINPUT"><strong>echo $BASH_VERSION</strong></code>
<code class="COMPUTEROUTPUT">BASH_VERSION: Undefined variable.</code>
             
</pre>
                  <br>
                  <br>

                  <p>Проверка переменной $BASH_VERSION -- неплохой
                  метод проверки типа командной оболочки, под которой
                  исполняется скрипт. Переменная <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SHELLVARREF">$SHELL</a> не всегда дает
                  правильный ответ.</p>
                </dd>

                <dt><a name="DIRSTACKREF"></a><code class="VARNAME">$DIRSTACK</code></dt>

                <dd>
                  <p>содержимое вершины стека каталогов (который
                  управляется командами <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PUSHDREF">pushd</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#POPDREF">popd</a>)</p>

                  <p>Эта переменная соответствует команде <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DIRSD">dirs</a>, за исключением того, что
                  <strong class="COMMAND">dirs</strong> показывает полное
                  содержимое всего стека каталогов.</p>
                </dd>

                <dt><code class="VARNAME">$EDITOR</code></dt>

                <dd>
                  <p>заданный по-умолчанию редактор, вызываемый
                  скриптом, обычно <strong class="COMMAND">vi</strong> или <strong class="COMMAND">emacs</strong>.</p>
                </dd>

                <dt><a name="EUIDREF"></a><code class="VARNAME">$EUID</code></dt>

                <dd>
                  <p><span class="QUOTE">"эффективный"</span>
                  идентификационный номер пользователя (Effective User
                  ID)</p>

                  <p>Идентификационный номер пользователя, права
                  которого были получены, возможно с помощью команды <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SUREF">su</a>.</p>

                  <div class="CAUTION">
                    <table class="CAUTION" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                        <td align="left" valign="top">
                          <p>Значение переменной <code class="VARNAME">$EUID</code> необязательно
                          должно совпадать с содержимым переменной <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#UIDREF">$UID</a>.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><code class="VARNAME">$FUNCNAME</code></dt>

                <dd>
                  <p>имя текущей функции</p>
<pre class="PROGRAMLISTING">xyz23 ()
{
  echo "Исполняется функция $FUNCNAME."  # Исполняется функция xyz23.
}

xyz23

echo "FUNCNAME = $FUNCNAME"        # FUNCNAME =
                                   # Пустое (Null) значение за пределеми функций.
</pre>
                  <br>
                  <br>
                </dd>

                <dt><code class="VARNAME">$GLOBIGNORE</code></dt>

                <dd>
                  <p>Перечень шаблонных символов, которые будут
                  проигнорированы при выполнении <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GLOBBINGREF">подстановки имен файлов
                  (globbing)</a> .</p>
                </dd>

                <dt><a name="GROUPSREF"></a><code class="VARNAME">$GROUPS</code></dt>

                <dd>
                  <p>группы, к которым принадлежит текущий
                  пользователь</p>

                  <p>Это список групп (массив) идентификационных
                  номеров групп для текущего пользователя, как эо
                  записано в <code class="FILENAME">/etc/passwd</code>.</p>
<pre class="SCREEN"><code class="PROMPT">root#</code> <code class="USERINPUT"><strong>echo $GROUPS</strong></code>
<code class="COMPUTEROUTPUT">0</code>


<code class="PROMPT">root#</code> <code class="USERINPUT"><strong>echo ${GROUPS[1]}</strong></code>
<code class="COMPUTEROUTPUT">1</code>


<code class="PROMPT">root#</code> <code class="USERINPUT"><strong>echo ${GROUPS[5]}</strong></code>
<code class="COMPUTEROUTPUT">6</code>
             
</pre>
                  <br>
                  <br>
                </dd>

                <dt><a name="HOMEDIRREF"></a><code class="VARNAME">$HOME</code></dt>

                <dd>
                  <p>домашний каталог пользователя, как правило это <code class="FILENAME">/home/username</code> (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX6">Пример 9-13</a>)</p>
                </dd>

                <dt><a name="HOSTNAMEREF"></a><code class="VARNAME">$HOSTNAME</code></dt>

                <dd>
                  <p>Сетевое имя хоста устанавливается командой <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#HNAMEREF">hostname</a> во время исполнения
                  инициализирующих сценариев на загрузке системы.
                  Внутренняя переменная <code class="VARNAME">$HOSTNAME</code> Bash получает свое
                  значение посредством вызова функции <code class="FUNCTION">gethostname()</code>. См. так же <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX6">Пример 9-13</a>.</p>
                </dd>

                <dt><code class="VARNAME">$HOSTTYPE</code></dt>

                <dd>
                  <p>тип машины</p>

                  <p>Подобно <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MACHTYPEREF">$MACHTYPE</a>, идентифицирует
                  аппаратную архитектуру.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo $HOSTTYPE</strong></code>
<code class="COMPUTEROUTPUT">i686</code>
</pre>
                </dd>

                <dt><a name="IFSREF"></a><code class="VARNAME">$IFS</code></dt>

                <dd>
                  <p>разделитель полей во вводимой строке (IFS -- Input
                  Field Separator)</p>

                  <p>По-умолчанию -- <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WHITESPACEREF">пробельный символ</a> (пробел,
                  табуляция и перевод строки), но может быть изменен,
                  например, для разбора строк, в которых отдельные поля
                  разделены запятыми. Обратите внимание: при
                  составлении содержимого переменной <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#APPREF">$*</a>, Bash использует первый символ
                  из <code class="VARNAME">$IFS</code> для разделения аргументов.
                  См. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WEIRDVARS">Пример 5-1</a>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo $IFS | cat -vte</strong></code>
<code class="COMPUTEROUTPUT">$</code>


<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>bash -c 'set w x y z; IFS=":-;"; echo "$*"'</strong></code>
<code class="COMPUTEROUTPUT">w:x:y:z</code>
             
</pre>
                  <br>
                  <br>

                  <div class="CAUTION">
                    <table class="CAUTION" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                        <td align="left" valign="top">
                          <p>При всем при том следует помнить, что при
                          использовании <code class="VARNAME">$IFS</code> пробельные символы
                          обрабатываются несколько иначе, чем все
                          остальные.</p>

                          <div class="EXAMPLE">
                            <a name="IFSH"></a>

                            <p><strong>Пример 9-1. $IFS и пробельные
                            символы</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# При использовании $IFS, пробельные символы обрабатываются иначе, чем все остальные.

output_args_one_per_line()
{
  for arg
  do echo "[$arg]"
  done
}

echo; echo "IFS=\" \""
echo "-------"

IFS=" "
var=" a  b c   "
output_args_one_per_line $var  # output_args_one_per_line `echo " a  b c   "`
#
# [a]
# [b]
# [c]


echo; echo "IFS=:"
echo "-----"

IFS=:
var=":a::b:c:::"               # То же самое, только пробелы зменены символом ":".
output_args_one_per_line $var
#
# []
# [a]
# []
# [b]
# [c]
# []
# []
# []

# То же самое происходит и с разделителем полей "FS" в awk.

# Спасибо Stephane Chazelas.

echo

exit 0
</pre>
                          </div>
                          <br>
                          <br>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>

                  <p>(Спасибо S. C., за разъяснения и примеры.)</p>
                </dd>

                <dt><code class="VARNAME">$LC_COLLATE</code></dt>

                <dd>
                  <p>Чаще всего устанавливается в <code class="FILENAME">.bashrc</code> или <code class="FILENAME">/etc/profile</code>, эта переменная
                  задает порядок сортировки символов, в операциях
                  подстановки имен файлов и в поиске по шаблону. При
                  неверной настройке переменной <code class="VARNAME">LC_COLLATE</code> можно получить
                  весьма неожиданные результаты.</p>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p>Начиная с версии 2.05, Bash, в операциях
                          подстановки имен файлов, не делает различий
                          между символами верхнего и нижнего регистров,
                          в диапазонах символов в квадратных скобках.
                          Например,, <strong class="COMMAND">ls [A-M]*</strong> выведет
                          как <code class="FILENAME">File1.txt</code>, так и <code class="FILENAME">file1.txt</code>. Возврат к
                          общепринятому стандарту поведения шаблонов в
                          квадратных скобках выполняется установкой
                          переменной <code class="VARNAME">LC_COLLATE</code> в значение
                          <code class="OPTION">C</code> командой <code class="USERINPUT"><strong>export
                          LC_COLLATE=C</strong></code> в файле <code class="FILENAME">/etc/profile</code> и/или <code class="FILENAME">~/.bashrc</code>.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><code class="VARNAME">$LC_CTYPE</code></dt>

                <dd>
                  <p>Эта внутренняя переменная определяет кодировку
                  символов. Используется в операциях <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GLOBBINGREF">подстановки</a> и поиске по
                  шаблону.</p>
                </dd>

                <dt><code class="VARNAME">$LINENO</code></dt>

                <dd>
                  <p>Номер строки исполняемого сценария. Эта переменная
                  имеет смысл только внутри исполняемого сценария и
                  чаще всего применяется в отладочных целях.</p>
<pre class="PROGRAMLISTING"># *** BEGIN DEBUG BLOCK ***
last_cmd_arg=$_  # Запомнить.

echo "Строка $LINENO: переменная \"v1\" = $v1"
echo "Последний аргумент командной строки = $last_cmd_arg"
# *** END DEBUG BLOCK ***
</pre>
                  <br>
                  <br>
                </dd>

                <dt><a name="MACHTYPEREF"></a><code class="VARNAME">$MACHTYPE</code></dt>

                <dd>
                  <p>аппаратная архитектура</p>

                  <p>Идентификатор аппаратной архитектуры.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo $MACHTYPE</strong></code>
<code class="COMPUTEROUTPUT">i686</code>
</pre>
                </dd>

                <dt><a name="OLDPWD"></a><code class="VARNAME">$OLDPWD</code></dt>

                <dd>
                  <p>прежний рабочий каталог (<span class="QUOTE">"OLD-Print-Working-Directory"</span>)</p>
                </dd>

                <dt><code class="VARNAME">$OSTYPE</code></dt>

                <dd>
                  <p>тип операционной системы</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo $OSTYPE</strong></code>
<code class="COMPUTEROUTPUT">linux</code>
</pre>
                </dd>

                <dt><a name="PAT"></a><code class="VARNAME">$PATH</code></dt>

                <dd>
                  <p>путь поиска, как правило включает в себя каталоги
                  <code class="FILENAME">/usr/bin/</code>, <code class="FILENAME">/usr/X11R6/bin/</code>, <code class="FILENAME">/usr/local/bin</code>, и т.д.</p>

                  <p>Когда командный интерпретатор получает команду, то
                  он автоматически пытается отыскать соответствующий
                  исполняемый файл в указанном списке каталогов (в
                  переменной $PATH). Каталоги, в указанном списке,
                  должны отделяться друг от друга двоеточиями. Обычно,
                  переменная <code class="VARNAME">$PATH</code> инициализируется в <code class="FILENAME">/etc/profile</code> и/или в <code class="FILENAME">~/.bashrc</code> (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FILES">Глава 26</a>).</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <strong class="COMMAND">echo $PATH</strong>
<code class="COMPUTEROUTPUT">/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin:/sbin:/usr/sbin</code>
</pre>
                  <br>
                  <br>

                  <p>Инструкция <code class="USERINPUT"><strong>PATH=${PATH}:/opt/bin</strong></code>
                  добавляет каталог <code class="FILENAME">/opt/bin</code> в конец текущего пути
                  поиска. Иногда может оказаться целесообразным, внутри
                  сценария, временно добавить какой-либо каталог к пути
                  поиска. По завершении работы скрипта, эти изменения
                  будут утеряны (вспомните о том, что невозможно
                  изменить переменные окружения вызывающего
                  процесса).</p>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p>Текущий <span class="QUOTE">"рабочий
                          каталог"</span>, <code class="FILENAME">./</code>, обычно не
                          включается в <code class="VARNAME">$PATH</code> из соображений
                          безопасности.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><code class="VARNAME">$PIPESTATUS</code></dt>

                <dd>
                  <p>Код возврата <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PIPEREF">канала (конвейера)</a>. Интересно,
                  что это не то же самое, что <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXITSTATUSREF">код возврата</a> последней
                  исполненной команды.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo $PIPESTATUS</strong></code>
<code class="COMPUTEROUTPUT">0</code>

<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>ls -al | bogus_command</strong></code>
<code class="COMPUTEROUTPUT">bash: bogus_command: command not found</code>
<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo $PIPESTATUS</strong></code>
<code class="COMPUTEROUTPUT">141</code>

<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>ls -al | bogus_command</strong></code>
<code class="COMPUTEROUTPUT">bash: bogus_command: command not found</code>
<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo $?</strong></code>
<code class="COMPUTEROUTPUT">127</code>
             
</pre>
                  <br>
                  <br>

                  <div class="CAUTION">
                    <table class="CAUTION" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                        <td align="left" valign="top">
                          <p>Переменная <code class="VARNAME">$PIPESTATUS</code> может
                          давать неверные значения при вызове из
                          командной строки.</p>
<pre class="SCREEN"><code class="PROMPT">tcsh%</code> <code class="USERINPUT"><strong>bash</strong></code>

<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>who | grep nobody | sort</strong></code>
<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo ${PIPESTATUS[*]}</strong></code>
<code class="COMPUTEROUTPUT">0</code>
             
</pre>
                          <br>
                          <br>

                          <p>Если поместить эти строки в сценарий и
                          исполнить его, то будут выведены верные
                          значения <code class="COMPUTEROUTPUT">0 1 0</code>.</p>

                          <p>Спасибо Wayne Pollock за замечания и
                          предоставленный пример.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><a name="PPIDREF"></a><code class="VARNAME">$PPID</code></dt>

                <dd>
                  <p>Переменная <code class="VARNAME">$PPID</code> хранит PID
                  (идентификатор) родительского процесса. <a name="AEN3728" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN3728"><span class="footnote">[19]</span></a></p>

                  <p>Сравните с командой <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PIDOFREF">pidof</a>.</p>
                </dd>

                <dt><a name="PS1REF"></a><code class="VARNAME">$PS1</code></dt>

                <dd>
                  <p>prompt, приглашение командной строки.</p>
                </dd>

                <dt><code class="VARNAME">$PS2</code></dt>

                <dd>
                  <p>Вторичное приглашение командной строки, выводится
                  тогда, когда от пользователя ожидается дополнительный
                  ввод. Отображается как <span class="QUOTE">"&gt;"</span>.</p>
                </dd>

                <dt><code class="VARNAME">$PS3</code></dt>

                <dd>
                  <p>Третичное приглашение (prompt), выводится тогда,
                  когда пользователь должен сделать выбор в операторе
                  <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SELECTREF">select</a> (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX31">Пример 10-29</a>).</p>
                </dd>

                <dt><code class="VARNAME">$PS4</code></dt>

                <dd>
                  <p>Приглашение (prompt) четвертого уровня, выводится
                  в начале каждой строки вывода тогда, когда сценарий
                  вызывается с <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#OPTIONSREF">ключом</a> <span class="TOKEN">-x</span>. Отображается как <span class="QUOTE">"+"</span>.</p>
                </dd>

                <dt><a name="PWDREF"></a><code class="VARNAME">$PWD</code></dt>

                <dd>
                  <p>рабочий (текущий) каталог</p>

                  <p>Аналог встроенной команды <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PWD2REF">pwd</a>.</p>
<pre class="PROGRAMLISTING">#!/bin/bash

E_WRONG_DIRECTORY=73

clear # Очистка экрана.

TargetDirectory=/home/bozo/projects/GreatAmericanNovel

cd $TargetDirectory
echo "Удаление файлов в каталоге $TargetDirectory."

if [ "$PWD" != "$TargetDirectory" ]
then    # Защита от случайного удаления файлов не в том каталоге.
  echo "Неверный каталог!"
  echo "Переменная $PWD указывает на другой каталог!"
  exit $E_WRONG_DIRECTORY
fi

rm -rf *
rm .[A-Za-z0-9]*    # удалить "скрытые" файлы (начинающиеся с ".")
# rm -f .[^.]* ..?*   удалить файлы, чьи имена начинаются с нескольких точек.
# (shopt -s dotglob; rm -f *)   тоже работает верно.
# Спасибо S.C. за замечание.

# Имена файлов могут содержать любые символы из диапазона 0-255, за исключением "/".
# Оставляю вопрос удаления файлов с "необычными" символами для самостоятельного изучения.

# Здесь можно вставить дополнительные действия, по мере необходимости.

echo
echo "Конец."
echo "Файлы, из каталога $TargetDirectory, удалены."
echo


exit 0
</pre>
                  <br>
                  <br>
                </dd>

                <dt><a name="REPLYREF"></a><code class="VARNAME">$REPLY</code></dt>

                <dd>
                  <p>переменная по-умолчанию, куда записывается ввод
                  пользователя, выполненный с помощью команды <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#READREF">read</a> если явно не задана другая
                  переменная. Так же может использоваться в операторе
                  <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SELECTREF">select</a>, для построения меню
                  выбора.</p>
<pre class="PROGRAMLISTING">#!/bin/bash

echo
echo -n "Ваше любимое растение? "
read

echo "Ваше любимое растение: $REPLY."
# REPLY хранит последнее значение, прочитанное командой "read" тогда, и только тогда
#+ когда команде "read" не передается имя переменной.

echo
echo -n "Ваш любимый фрукт? "
read fruit
echo "Ваш любимый фрукт $fruit."
echo "но..."
echo "Значение переменной \$REPLY осталось равным $REPLY."
# Переменная $REPLY не была перезаписана потому, что
# следующей команде "read", в качестве аргумента была передана переменная $fruit

echo

exit 0
</pre>
                  <br>
                  <br>
                </dd>

                <dt><code class="VARNAME">$SECONDS</code></dt>

                <dd>
                  <p>Время паботы сценария в секундах.</p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Автор: Mendel Cooper
# Дополнен переводчиком.
#

TIME_LIMIT=10
INTERVAL=1

echo
echo "Для прерывания работы сценария, ранее чем через $TIME_LIMIT секунд, нажмите Control-C."
echo

while [ "$SECONDS" -le "$TIME_LIMIT" ]
do
# Оригинальный вариант сценария содержал следующие строки
#  if [ "$SECONDS" -eq 1 ]
#  then
#    units=second
#  else
#    units=seconds
#  fi
#
# Однако, из-за того, что в русском языке для описания множественного числа
# существует большее число вариантов, чем в английском,
# переводчик позволил себе смелость несколько подправить сценарий
# (прошу ногами не бить! ;-) )
# === НАЧАЛО БЛОКА ИЗМЕНЕНИЙ, ВНЕСЕННЫХ ПЕРЕВОДЧИКОМ ===

  let "last_two_sym = $SECONDS - $SECONDS / 100 * 100" # десятки и единицы
  if [ "$last_two_sym" -ge 11 -a "$last_two_sym" -le 19 ]
  then
    units="секунд"               # для чисел, которые заканчиваются на "...надцать"
  else
    let "last_sym = $last_two_sym - $last_two_sym / 10 * 10"  # единицы
    case "$last_sym" in
      "1" )
        units="секунду"         # для чисел, заканчивающихся на 1
      ;;
      "2" | "3" | "4" )
        units="секунды"         # для чисел, заканчивающихся на 2, 3 и 4
      ;;
      * )
        units="секунд"          # для всех остальных (0, 5, 6, 7, 8, 9)
      ;;
    esac
  fi
# === КОНЕЦ БЛОКА ИЗМЕНЕНИЙ, ВНЕСЕННЫХ ПЕРЕВОДЧИКОМ ===

  echo "Сценарий отработал $SECONDS $units."
  #  В случае перегруженности системы, скрипт может перескакивать через отдельные
  #+  значения счетчика
  sleep $INTERVAL
done

echo -e "\a"  # Сигнал!

exit 0
</pre>
                  <br>
                  <br>
                </dd>

                <dt><code class="VARNAME">$SHELLOPTS</code></dt>

                <dd>
                  <p>список допустимых <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#OPTIONSREF">опций</a> интерпретатора shell.
                  Переменная доступна только для чтения.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo $SHELLOPTS</strong></code>
<code class="COMPUTEROUTPUT">braceexpand:hashall:histexpand:monitor:history:interactive-comments:emacs</code>
             
</pre>
                  <br>
                  <br>
                </dd>

                <dt><code class="VARNAME">$SHLVL</code></dt>

                <dd>
                  <p>Уровень вложенности shell. Если в командной
                  строке</p>
<pre class="SCREEN">echo $SHLVL
</pre>
                  дает 1, то в сценарии значение этой переменной будет
                  больше на 1, т.е. 2.<br>
                  <br>
                </dd>

                <dt><code class="VARNAME">$TMOUT</code></dt>

                <dd>
                  <p>Если переменная окружения <code class="REPLACEABLE"><em>$TMOUT</em></code> содержит
                  ненулевое значение, то интерпретатор будет ожидать
                  ввод не более чем заданное число секунд, что, в
                  первичном приглашении (см. описание PS1 выше), может
                  привести к автоматическому завершению сеанса
                  работы.</p>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p>К сожалению это возможно только во время
                          ожидания ввода с консоли или в окне
                          терминала. А как было бы здорово, если бы
                          можно было использовать эту внутреннюю
                          переменную, скажем в комбинации с командой <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#READREF">read</a>! Но в данном
                          контексте эта переменная абсолютно не
                          применима и потому фактически бесполезна в
                          сценариях. (Есть сведения о том, что в <span class="emphasis"><em class="EMPHASIS">ksh</em></span> время
                          ожидания ввода командой <strong class="COMMAND">read</strong> можно
                          ограничить.)</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>

                  <p>Организация ограничения времени ожидания ввода от
                  пользователя в сценариях возможна, но это требут
                  довольно сложных махинаций. Как один из вариантов,
                  можно предложить организовать прерывание цикла
                  ожидания по сигналу. Но это потребует написание
                  функции обработки сигналов командой trap (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX76">Пример 29-5</a>).</p>

                  <div class="EXAMPLE">
                    <a name="TMDIN"></a>

                    <p><strong>Пример 9-2. Ограничения времени ожидания
                    ввода</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# timed-input.sh

# TMOUT=3            бесполезно в сценариях

TIMELIMIT=3  # Три секунды в данном случае, но может быть установлено и другое значение

PrintAnswer()
{
  if [ "$answer" = TIMEOUT ]
  then
    echo $answer
  else       # Чтобы не спутать разные варианты вывода.
    echo "Ваше любимое растение $answer"
    kill $!  # "Прибить" ненужную больше функцию TimerOn, запущенную в фоновом процессе.
             # $! -- PID последнего процесса, запущенного в фоне.
  fi

}



TimerOn()
{
  sleep $TIMELIMIT &amp;&amp; kill -s 14 $$ &amp;
  # Ждать 3 секунды, после чего выдать sigalarm сценарию.
}

Int14Vector()
{
  answer="TIMEOUT"
  PrintAnswer
  exit 14
}

trap Int14Vector 14   # переназначить процедуру обработки прерывания от таймера (14)

echo "Ваше любимое растение? "
TimerOn
read answer
PrintAnswer


#  По общему признанию, это не очень хороший способ ограничения времени ожидания,
#+ однако опция "-t"команды "read" упрощает задачу.
#  См. "t-out.sh", ниже.

#  Если вам нужно что-то более элегантное...
#+ подумайте о написании программы на C или C++,
#+ с использованием соответствующих библиотечных функций, таких как 'alarm' и 'setitimer'.

exit 0
</pre>
                  </div>

                  <p>В качестве альтернативы можно использовать <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#STTYREF">stty</a>.</p>

                  <div class="EXAMPLE">
                    <a name="TIMEOUT"></a>

                    <p><strong>Пример 9-3. Еще один пример ограничения
                    времени ожидания ввода от пользователя</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# timeout.sh

# Автор: Stephane Chazelas,
# дополнен автором документа.

INTERVAL=5                # предел времени ожидания

timedout_read() {
  timeout=$1
  varname=$2
  old_tty_settings=`stty -g`
  stty -icanon min 0 time ${timeout}0
  eval read $varname      # или просто    read $varname
  stty "$old_tty_settings"
  # См. man stty.
}

echo; echo -n "Как Вас зовут? Отвечайте быстрее! "
timedout_read $INTERVAL your_name

# Такой прием может не работать на некоторых типах терминалов.
# Максимальное время ожидания зависит от терминала.
# (чаще всего это 25.5 секунд).

echo

if [ ! -z "$your_name" ]  # Если имя было введено...
then
  echo "Вас зовут $your_name."
else
  echo "Вы не успели ответить."
fi

echo

# Алгоритм работы этого сценария отличается от "timed-input.sh".
# Каждое нажатие на клавишу вызывает сброс счетчика в начальное состояние.

exit 0
</pre>
                  </div>

                  <p>Возможно самый простой способ -- использовать
                  опцию <code class="OPTION">-t</code> команды <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#READREF">read</a>.</p>

                  <div class="EXAMPLE">
                    <a name="TOUT"></a>

                    <p><strong>Пример 9-4. Ограничение времени ожидания
                    команды read</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# t-out.sh 

TIMELIMIT=4        # 4 секунды

read -t $TIMELIMIT variable &lt;&amp;1

echo

if [ -z "$variable" ]
then
  echo "Время ожидания истекло."
else
  echo "variable = $variable"
fi  

exit 0
</pre>
                  </div>
                </dd>

                <dt><a name="UIDREF"></a><code class="VARNAME">$UID</code></dt>

                <dd>
                  <p>user id number</p>

                  <p>UID (идентификатор) текущего пользователя, в
                  соответствии с <code class="FILENAME">/etc/passwd</code></p>

                  <p>Это реальный UID текущего пользователя, даже если
                  он временно приобрел права другого пользователя с
                  помощью <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SUREF">su</a>. Переменная <code class="VARNAME">$UID</code> доступна только для
                  чтения.</p>

                  <div class="EXAMPLE">
                    <a name="AMIROOT"></a>

                    <p><strong>Пример 9-5. Я -- root?</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# am-i-root.sh:   Root я, или не root?

ROOT_UID=0   # $UID root-а всегда равен 0.

if [ "$UID" -eq "$ROOT_UID" ]  # Настоящий "root"?
then
  echo "- root!"
else
  echo "простой пользователь (но мамочка вас тоже любит)!"
fi

exit 0


# ============================================================= #
#  Код, приведенный ниже, никогда не отработает,
#+ поскольку работа сценария уже завершилась выше

# Еще один способ отличить root-а от не root-а:

ROOTUSER_NAME=root

username=`id -nu`              # Или...   username=`whoami`
if [ "$username" = "$ROOTUSER_NAME" ]
then
  echo "Рутти-тутти. - root!"
else
  echo "Вы - лишь обычный юзер."
fi
</pre>
                  </div>

                  <p>См. также <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX2">Пример 2-2</a>.</p>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p>Переменные <code class="VARNAME">$ENV</code>, <code class="VARNAME">$LOGNAME</code>, <code class="VARNAME">$MAIL</code>, <code class="VARNAME">$TERM</code>, <code class="VARNAME">$USER</code> и <code class="VARNAME">$USERNAME</code>, не являются
                          <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BUILTINREF">встроенными</a>
                          переменными Bash. Тем не менее, они часто
                          инициализируются как <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ENVREF">переменные окружения</a> в
                          одном из <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FILESREF1">стартовых файлов</a> Bash.
                          <a name="SHELLVARREF"></a>Переменная <code class="VARNAME">$SHELL</code>, командная
                          оболочка пользователя, может задаваться в <code class="FILENAME">/etc/passwd</code> или в
                          сценарии <span class="QUOTE">"init"</span> и она
                          тоже не является встроенной переменной
                          Bash.</p>
<pre class="SCREEN"><code class="PROMPT">tcsh%</code> <code class="USERINPUT"><strong>echo $LOGNAME</strong></code>
<code class="COMPUTEROUTPUT">bozo</code>
<code class="PROMPT">tcsh%</code> <code class="USERINPUT"><strong>echo $SHELL</strong></code>
<code class="COMPUTEROUTPUT">/bin/tcsh</code>
<code class="PROMPT">tcsh%</code> <code class="USERINPUT"><strong>echo $TERM</strong></code>
<code class="COMPUTEROUTPUT">rxvt</code>

<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo $LOGNAME</strong></code>
<code class="COMPUTEROUTPUT">bozo</code>
<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo $SHELL</strong></code>
<code class="COMPUTEROUTPUT">/bin/tcsh</code>
<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo $TERM</strong></code>
<code class="COMPUTEROUTPUT">rxvt</code>
             
</pre>
                          <br>
                          <br>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>
              </dl>
            </div>

            <div class="VARIABLELIST">
              <p><strong>Позиционные параметры (аргументы)</strong></p>

              <dl>
                <dt><a name="POSPARAMREF"></a><code class="VARNAME">$0</code>, <code class="VARNAME">$1</code>, <code class="VARNAME">$2</code> и т.д.</dt>

                <dd>
                  <p>аргументы передаются... из командной строки в
                  сценарий, функциям или команде <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SETREF">set</a> (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX17">Пример 4-5</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX34">Пример 11-13</a>)</p>
                </dd>

                <dt><code class="VARNAME">$#</code></dt>

                <dd>
                  <p>количество аргументов командной строки <a name="AEN4011" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN4011"><span class="footnote">[20]</span></a>, или позиционных
                  параметров (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX4">Пример 33-2</a>)</p>
                </dd>

                <dt><a name="APPREF"></a><code class="VARNAME">$*</code></dt>

                <dd>
                  <p>Все аргументы в виде одной строки (слова)</p>
                </dd>

                <dt><code class="VARNAME">$@</code></dt>

                <dd>
                  <p>То же самое, что и <span class="TOKEN">$*</span>, но при этом каждый параметр
                  представлен как отдельная строка (слово), т.е.
                  параметры не подвергаются какой либо
                  интерпретации.</p>

                  <div class="EXAMPLE">
                    <a name="ARGLIST"></a>

                    <p><strong>Пример 9-6. arglist: Вывод списка
                    аргументов с помощью переменных $* и
                    $@</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Вызовите сценарий с несколькими аргументами, например: "один два три".

E_BADARGS=65

if [ ! -n "$1" ]
then
  echo "Порядок использования: `basename $0` argument1 argument2 и т.д."
  exit $E_BADARGS
fi

echo

index=1

echo "Список аргументов в переменной \"\$*\":"
for arg in "$*"  # Работает некорректно, если "$*" не ограничена кавычками.
do
  echo "Аргумент #$index = $arg"
  let "index+=1"
done             # $* воспринимает все аргументы как одну строку.
echo "Полный список аргументов выглядит как одна строка."

echo

index=1

echo "Список аргументов в переменной \"\$@\":"
for arg in "$@"
do
  echo "Аргумент #$index = $arg"
  let "index+=1"
done             # $@ воспринимает аргументы как отдельные строки (слова).
echo "Список аргументов выглядит как набор различных строк (слов)."

echo

exit 0
</pre>
                  </div>

                  <p>После команды <strong class="COMMAND">shift</strong> (сдвиг), первый
                  аргумент, в переменной <code class="VARNAME">$@</code>, теряется, а остальные
                  сдвигаются на одну позицию "вниз" (или
                  "влево", если хотите).</p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Вызовите сценарий в таком виде: ./scriptname 1 2 3 4 5

echo "$@"    # 1 2 3 4 5
shift
echo "$@"    # 2 3 4 5
shift
echo "$@"    # 3 4 5

# Каждая из команд "shift" приводит к потере аргумента $1,
# но остальные аргументы остаются в "$@".
</pre>
                  <br>
                  <br>

                  <p>Специальная переменная <code class="VARNAME">$@</code> может быть использована для
                  выбора типа ввода в сценария. Команда <strong class="COMMAND">cat "$@"</strong>
                  позволяет выполнять ввод как со стандартного
                  устройства ввода <code class="FILENAME">stdin</code>, так и из файла, имя
                  которого передается сценарию из командной строки. См.
                  <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ROT13">Пример 12-17</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CRYPTOQUOTE">Пример 12-18</a>.</p>

                  <div class="CAUTION">
                    <table class="CAUTION" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                        <td align="left" valign="top">
                          <p>Переменные <code class="VARNAME">$*</code> и <code class="VARNAME">$@</code>, в отдельных
                          случаях, могут содержать противоречивую
                          информацию! Это зависит от содержимого
                          переменной <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IFSREF">$IFS</a>.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>

                  <div class="EXAMPLE">
                    <a name="INCOMPAT"></a>

                    <p><strong>Пример 9-7. Противоречия в переменных
                    <code class="VARNAME">$*</code> и <code class="VARNAME">$@</code></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

#  Демонстрация противоречивости содержимого внутренних переменных "$*" и "$@",
#+ которая проявляется при изменении порядка заключения параметров в кавычки.
#  Демонстрация противоречивости, проявляющейся при изменении
#+ содержимого переменной IFS.


set -- "Первый один" "второй" "третий:один" "" "Пятый: :один"
# Установка аргументов $1, $2, и т.д.

echo

echo 'IFS по-умолчанию, переменная "$*"'
c=0
for i in "$*"               # в кавычках
do echo "$((c+=1)): [$i]"   # Эта строка остается без изменений во всех циклах.
                            # Вывод аргументов.
done
echo ---

echo 'IFS по-умолчанию, переменная $*'
c=0
for i in $*                 # без кавычек
do echo "$((c+=1)): [$i]"
done
echo ---

echo 'IFS по-умолчанию, переменная "$@"'
c=0
for i in "$@"
do echo "$((c+=1)): [$i]"
done
echo ---

echo 'IFS по-умолчанию, переменная $@'
c=0
for i in $@
do echo "$((c+=1)): [$i]"
done
echo ---

IFS=:
echo 'IFS=":", переменная "$*"'
c=0
for i in "$*"
do echo "$((c+=1)): [$i]"
done
echo ---

echo 'IFS=":", переменная $*'
c=0
for i in $*
do echo "$((c+=1)): [$i]"
done
echo ---

var=$*
echo 'IFS=":", переменная "$var" (var=$*)'
c=0
for i in "$var"
do echo "$((c+=1)): [$i]"
done
echo ---

echo 'IFS=":", переменная $var (var=$*)'
c=0
for i in $var
do echo "$((c+=1)): [$i]"
done
echo ---

var="$*"
echo 'IFS=":", переменная $var (var="$*")'
c=0
for i in $var
do echo "$((c+=1)): [$i]"
done
echo ---

echo 'IFS=":", переменная "$var" (var="$*")'
c=0
for i in "$var"
do echo "$((c+=1)): [$i]"
done
echo ---

echo 'IFS=":", переменная "$@"'
c=0
for i in "$@"
do echo "$((c+=1)): [$i]"
done
echo ---

echo 'IFS=":", переменная $@'
c=0
for i in $@
do echo "$((c+=1)): [$i]"
done
echo ---

var=$@
echo 'IFS=":", переменная $var (var=$@)'
c=0
for i in $var
do echo "$((c+=1)): [$i]"
done
echo ---

echo 'IFS=":", переменная "$var" (var=$@)'
c=0
for i in "$var"
do echo "$((c+=1)): [$i]"
done
echo ---

var="$@"
echo 'IFS=":", переменная "$var" (var="$@")'
c=0
for i in "$var"
do echo "$((c+=1)): [$i]"
done
echo ---

echo 'IFS=":", переменная $var (var="$@")'
c=0
for i in $var
do echo "$((c+=1)): [$i]"
done

echo

# Попробуйте запустить этот сценарий под ksh или zsh -y.

exit 0

# Это сценарий написан Stephane Chazelas,
# Незначительные изменения внесены автором документа.
</pre>
                  </div>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p>Различия между <strong class="COMMAND">$@</strong> и <strong class="COMMAND">$*</strong> наблюдаются
                          только тогда, когда они помещаются в двойные
                          кавычки.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>

                  <div class="EXAMPLE">
                    <a name="IFSEMPTY"></a>

                    <p><strong>Пример 9-8. Содержимое <code class="VARNAME">$*</code> и <code class="VARNAME">$@</code>, когда переменная <code class="VARNAME">$IFS</code> -- пуста</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# Если переменная $IFS инициализирована "пустым" значением,
# то "$*" и "$@" содержат аргументы не в том виде, в каком ожидается.

mecho ()       # Вывод аргументов.
{
echo "$1,$2,$3";
}


IFS=""         # Инициализация "пустым" значением.
set a b c      # Установка аргументов.

mecho "$*"     # abc,,
mecho $*       # a,b,c

mecho $@       # a,b,c
mecho "$@"     # a,b,c

# Поведение переменных $* и $@, при "пустой" $IFS, зависит
# от версии командной оболочки, Bash или sh.
# Поэтому, было бы неразумным пользоваться этой "фичей" в своих сценариях.


# Спасибо S.C.

exit 0
</pre>
                  </div>
                </dd>
              </dl>
            </div>

            <div class="VARIABLELIST">
              <p><strong>Прочие специальные переменные</strong></p>

              <dl>
                <dt><a name="FLPREF"></a><code class="VARNAME">$-</code></dt>

                <dd>
                  <p>Список флагов, переданных сценарию (командой <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SETREF">set</a>). См. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX34">Пример 11-13</a>.</p>

                  <div class="CAUTION">
                    <table class="CAUTION" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                        <td align="left" valign="top">
                          <p>Эта конструкция изначально была введена в
                          <span class="emphasis"><em class="EMPHASIS">ksh</em></span>, откуда
                          перекочевала в Bash и, похоже, работает в
                          Bash не совсем надежно. Единственное
                          возможное применение -- <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IITEST">проверка - запущен ли
                          сценарий в интерактивном режиме</a>.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><code class="VARNAME">$!</code></dt>

                <dd>
                  <p>PID последнего, запущенного в фоне, процесса</p>
<pre class="PROGRAMLISTING">LOG=$0.log

COMMAND1="sleep 100"

echo "Запись в лог всех PID фоновых процессов, запущенных из сценария: $0" &gt;&gt; "$LOG"
# Таким образом возможен мониторинг и удаление процессов по мере необходимости.
echo &gt;&gt; "$LOG"

# Команды записи в лог.

echo -n "PID of \"$COMMAND1\":  " &gt;&gt; "$LOG"
${COMMAND1} &amp;
echo $! &gt;&gt; "$LOG"
# PID процесса "sleep 100":  1506

# Спасибо Jacques Lederer за предложенный пример.
</pre>
                  <br>
                  <br>
                </dd>

                <dt><a name="UNDERSCOREREF"></a><code class="VARNAME">$_</code></dt>

                <dd>
                  <p>Специальная переменная, содержит последний
                  аргумент предыдущей команды.</p>

                  <div class="EXAMPLE">
                    <a name="USCREF"></a>

                    <p><strong>Пример 9-9. Переменная
                    "подчеркивание"</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

echo $_              # /bin/bash
                     # Для запуска сценария был вызван /bin/bash.

du &gt;/dev/null        # Подавление вывода.
echo $_              # du

ls -al &gt;/dev/null    # Подавление вывода.
echo $_              # -al  (последний аргумент)

:
echo $_              # :
</pre>
                  </div>
                </dd>

                <dt><a name="XSTATVARREF"></a><code class="VARNAME">$?</code></dt>

                <dd>
                  <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXITSTATUSREF">Код возврата</a> команды, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FUNCTIONREF">функции</a> или скрипта (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MAX">Пример 22-3</a>)</p>
                </dd>

                <dt><a name="PROCCID"></a><code class="VARNAME">$$</code></dt>

                <dd>
                  <p>PID самого процесса-сценария. Переменная <code class="VARNAME">$$</code> часто используется при
                  генерации "уникальных" имен для временных
                  файлов (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTPGET">Пример A-14</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ONLINE">Пример 29-6</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DERPM">Пример 12-23</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SELFDESTRUCT">Пример 11-23</a>). Обычно это
                  проще чем вызов <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MKTEMPREF">mktemp</a>.</p>
                </dd>
              </dl>
            </div>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="STRING-MANIPULATION"></a>9.2. Работа со
            строками</h2>

            <p><a name="STRINGMANIP"></a></p>

            <p>Bash поддерживает на удивление большое количество
            операций над строками. К сожалению, этот раздел Bash
            испытывает недостаток унификации. Одни операции являются
            подмножеством операций <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PARAMSUBREF">подстановки параметров</a>, а другие
            -- совпадают с функциональностью команды UNIX -- <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXPRREF">expr</a>. Это приводит к противоречиям в
            синтаксисе команд и перекрытию функциональных возможностей,
            не говоря уже о возникающей путанице.</p>

            <div class="VARIABLELIST">
              <p><strong>Длина строки</strong></p>

              <dl>
                <dt>${#string}</dt>

                <dt>expr length $string</dt>

                <dt>expr "$string" : '.*'</dt>

                <dd>
<pre class="PROGRAMLISTING">stringZ=abcABC123ABCabc

echo ${#stringZ}                 # 15
echo `expr length $stringZ`      # 15
echo `expr "$stringZ" : '.*'`    # 15
</pre>
                  <br>
                  <br>
                </dd>
              </dl>
            </div>

            <div class="EXAMPLE">
              <a name="PARAGRAPHSPACE"></a>

              <p><strong>Пример 9-10. Вставка пустых строк между
              параграфами в текстовом файле</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# paragraph-space.sh

# Вставка пустых строк между параграфами в текстовом файле.
# Порядок использования: $0 &lt;FILENAME

MINLEN=45        # Возможно потребуется изменить это значение.
#  Строки, содержащие количество символов меньшее, чем $MINLEN
#+ принимаются за последнюю строку параграфа.

while read line  # Построчное чтение файла от начала до конца...
do
  echo "$line"   # Вывод строки.

  len=${#line}
  if [ "$len" -lt "$MINLEN" ]
    then echo    # Добавление пустой строки после последней строки параграфа.
  fi  
done

exit 0
</pre>
            </div>

            <div class="VARIABLELIST">
              <p><strong>Длина подстроки в строке (подсчет совпадающих
              символов ведется с начала строки)</strong></p>

              <dl>
                <dt>expr match "$string"
                '$substring'</dt>

                <dd>
                  <p>где <code class="REPLACEABLE"><em>$substring</em></code> -- <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REGEXREF">регулярное выражение</a>.</p>
                </dd>

                <dt>expr "$string" :
                '$substring'</dt>

                <dd>
                  <p>где <code class="REPLACEABLE"><em>$substring</em></code> --
                  регулярное выражение.</p>

                  <p>
</p>
<pre class="PROGRAMLISTING">stringZ=abcABC123ABCabc
#       |------|

echo `expr match "$stringZ" 'abc[A-Z]*.2'`   # 8
echo `expr "$stringZ" : 'abc[A-Z]*.2'`       # 8
</pre>
                  <br>
                  <br>
                </dd>
              </dl>
            </div>

            <div class="VARIABLELIST">
              <p><strong>Index</strong></p>

              <dl>
                <dt>expr index $string $substring</dt>

                <dd>
                  <p>Номер позиции первого совпадения в $string c
                  первым символом в $substring.</p>
<pre class="PROGRAMLISTING">stringZ=abcABC123ABCabc
echo `expr index "$stringZ" C12`             # 6
                                             # позиция символа C.

echo `expr index "$stringZ" 1c`              # 3
# символ 'c' (в #3 позиции) совпал раньше, чем '1'.
</pre>
                  <br>
                  <br>

                  <p>Эта функция довольно близка к функции <span class="emphasis"><em class="EMPHASIS">strchr()</em></span> в языке C.</p>
                </dd>
              </dl>
            </div>

            <div class="VARIABLELIST">
              <p><strong>Извлечение подстроки</strong></p>

              <dl>
                <dt>${string:position}</dt>

                <dd>
                  <p>Извлекает подстроку из <code class="REPLACEABLE"><em>$string</em></code>, начиная с
                  позиции <code class="REPLACEABLE"><em>$position</em></code>.</p>

                  <p>Если строка <code class="VARNAME">$string</code> -- <span class="QUOTE">"<span class="TOKEN">*</span>"</span> или <span class="QUOTE">"<span class="TOKEN">@</span>"</span>, то извлекается
                  <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#POSPARAMREF">позиционный параметр</a>
                  (аргумент), <a name="AEN4257" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN4257"><span class="footnote">[21]</span></a> с номером <code class="VARNAME">$position</code>.</p>
                </dd>

                <dt>${string:position:length}</dt>

                <dd>
                  <p>Извлекает <code class="REPLACEABLE"><em>$length</em></code> символов
                  из <code class="REPLACEABLE"><em>$string</em></code>, начиная с
                  позиции <code class="REPLACEABLE"><em>$position</em></code>.</p>
<pre class="PROGRAMLISTING">stringZ=abcABC123ABCabc
#       0123456789.....
#       Индексация начинается с 0.

echo ${stringZ:0}                            # abcABC123ABCabc
echo ${stringZ:1}                            # bcABC123ABCabc
echo ${stringZ:7}                            # 23ABCabc

echo ${stringZ:7:3}                          # 23A
                                             # Извлекает 3 символа.



# Возможна ли индексация с "правой" стороны строки?

echo ${stringZ:-4}                           # abcABC123ABCabc
# По-умолчанию выводится полная строка.
# Однако . . .

echo ${stringZ:(-4)}                         # Cabc
echo ${stringZ: -4}                          # Cabc
# Теперь выводится правильно.
# Круглые скобки или дополнительный пробел "экранируют" параметр позиции.

# Спасибо Dan Jacobson, за разъяснения.
</pre>
                  <br>
                  <br>

                  <p>Если <code class="VARNAME">$string</code> -- <span class="QUOTE">"<span class="TOKEN">*</span>"</span> или <span class="QUOTE">"<span class="TOKEN">@</span>"</span>, то извлекается
                  до <code class="VARNAME">$length</code> позиционных параметров
                  (аргументов), начиная с <code class="VARNAME">$position</code>.</p>
<pre class="PROGRAMLISTING">echo ${*:2}          # Вывод 2-го и последующих аргументов.
echo ${@:2}          # То же самое.

echo ${*:2:3}        # Вывод 3-х аргументов, начиная со 2-го.
</pre>
                  <br>
                  <br>
                </dd>

                <dt>expr substr $string $position $length</dt>

                <dd>
                  <p>Извлекает <code class="REPLACEABLE"><em>$length</em></code> символов
                  из <code class="REPLACEABLE"><em>$string</em></code>, начиная с
                  позиции <code class="REPLACEABLE"><em>$position</em></code>.</p>
<pre class="PROGRAMLISTING">stringZ=abcABC123ABCabc
#       123456789......
#       Индексация начинается с 1.

echo `expr substr $stringZ 1 2`              # ab
echo `expr substr $stringZ 4 3`              # ABC
</pre>
                  <br>
                  <br>

                  <p><a name="EXPRPAREN"></a></p>
                </dd>

                <dt>expr match "$string"
                '\($substring\)'</dt>

                <dd>
                  <p>Находит и извлекает первое совпадение <code class="REPLACEABLE"><em>$substring</em></code> в <code class="REPLACEABLE"><em>$string</em></code>, где <code class="REPLACEABLE"><em>$substring</em></code> -- это
                  <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REGEXREF">регулярное выражение</a>.</p>
                </dd>

                <dt>expr "$string" :
                '\($substring\)'</dt>

                <dd>
                  <p>Находит и извлекает первое совпадение <code class="REPLACEABLE"><em>$substring</em></code> в <code class="REPLACEABLE"><em>$string</em></code>, где <code class="REPLACEABLE"><em>$substring</em></code> -- это
                  регулярное выражение.</p>
<pre class="PROGRAMLISTING">stringZ=abcABC123ABCabc
#       =======

echo `expr match "$stringZ" '\(.[b-c]*[A-Z]..[0-9]\)'`   # abcABC1
echo `expr "$stringZ" : '\(.[b-c]*[A-Z]..[0-9]\)'`       # abcABC1
echo `expr "$stringZ" : '\(.......\)'`                   # abcABC1
# Все вышеприведенные операции дают один и тот же результат.
</pre>
                  <br>
                  <br>
                </dd>

                <dt>expr match "$string"
                '.*\($substring\)'</dt>

                <dd>
                  <p>Находит и извлекает первое совпадение <code class="REPLACEABLE"><em>$substring</em></code> в <code class="REPLACEABLE"><em>$string</em></code>, где <code class="REPLACEABLE"><em>$substring</em></code> -- это
                  регулярное выражение. Поиск начинается с конца <code class="REPLACEABLE"><em>$string</em></code>.</p>
                </dd>

                <dt>expr "$string" :
                '.*\($substring\)'</dt>

                <dd>
                  <p>Находит и извлекает первое совпадение <code class="REPLACEABLE"><em>$substring</em></code> в <code class="REPLACEABLE"><em>$string</em></code>, где <code class="REPLACEABLE"><em>$substring</em></code> -- это
                  регулярное выражение. Поиск начинается с конца <code class="REPLACEABLE"><em>$string</em></code>.</p>
<pre class="PROGRAMLISTING">stringZ=abcABC123ABCabc
#                ======

echo `expr match "$stringZ" '.*\([A-C][A-C][A-C][a-c]*\)'`    # ABCabc
echo `expr "$stringZ" : '.*\(......\)'`                       # ABCabc
</pre>
                  <br>
                  <br>
                </dd>
              </dl>
            </div>

            <div class="VARIABLELIST">
              <p><strong>Удаление части строки</strong></p>

              <dl>
                <dt>${string#substring}</dt>

                <dd>
                  <p>Удаление самой короткой, из найденных, подстроки
                  <code class="REPLACEABLE"><em>$substring</em></code> в
                  строке <code class="REPLACEABLE"><em>$string</em></code>. Поиск
                  ведется с начала строки</p>
                </dd>

                <dt>${string##substring}</dt>

                <dd>
                  <p>Удаление самой длинной, из найденных, подстроки
                  <code class="REPLACEABLE"><em>$substring</em></code> в
                  строке <code class="REPLACEABLE"><em>$string</em></code>. Поиск
                  ведется с начала строки</p>
<pre class="PROGRAMLISTING">stringZ=abcABC123ABCabc
#       |----|
#       |----------|

echo ${stringZ#a*C}      # 123ABCabc
# Удаление самой короткой подстроки.

echo ${stringZ##a*C}     # abc
# Удаление самой длинной подстроки.
</pre>
                  <br>
                  <br>
                </dd>

                <dt>${string%substring}</dt>

                <dd>
                  <p>Удаление самой короткой, из найденных, подстроки
                  <code class="REPLACEABLE"><em>$substring</em></code> в
                  строке <code class="REPLACEABLE"><em>$string</em></code>. Поиск
                  ведется с конца строки</p>
                </dd>

                <dt>${string%%substring}</dt>

                <dd>
                  <p>Удаление самой длинной, из найденных, подстроки
                  <code class="REPLACEABLE"><em>$substring</em></code> в
                  строке <code class="REPLACEABLE"><em>$string</em></code>. Поиск
                  ведется с конца строки</p>
<pre class="PROGRAMLISTING">stringZ=abcABC123ABCabc
#                    ||
#        |------------|

echo ${stringZ%b*c}      # abcABC123ABCa
# Удаляется самое короткое совпадение. Поиск ведется с конца $stringZ.

echo ${stringZ%%b*c}     # a
# Удаляется самое длинное совпадение. Поиск ведется с конца $stringZ.
</pre>
                  <br>
                  <br>

                  <div class="EXAMPLE">
                    <a name="CVT"></a>

                    <p><strong>Пример 9-11. Преобразование графических
                    файлов из одного формата в другой, с изменением
                    имени файла</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
#  cvt.sh:
#  Преобразование всех файлов в заданном  каталоге,
#+ из графического формата MacPaint, в формат "pbm".

#  Используется утилита "macptopbm", входящая в состав пакета "netpbm",
#+ который сопровождается Brian Henderson (bryanh@giraffe-data.com).
#  Netpbm -- стандартный пакет для большинства дистрибутивов Linux.

OPERATION=macptopbm
SUFFIX=pbm          # Новое расширение файла.

if [ -n "$1" ]
then
  directory=$1      # Если каталог задан в командной строке при вызове сценария
else
  directory=$PWD    # Иначе просматривается текущий каталог.
fi

#  Все файлы в каталоге, имеющие расширение ".mac", считаются файлами
#+ формата  MacPaint.

for file in $directory/* # Подстановка имен файлов.
do
  filename=${file%.*c}   #  Удалить расширение ".mac" из имени файла
                         #+ ( с шаблоном '.*c' совпадают все подстроки
                         #+ начинающиеся с '.' и заканчивающиеся 'c',
  $OPERATION $file &gt; "$filename.$SUFFIX"
                         # Преобразование с перенаправлением в файл с новым именем
  rm -f $file            # Удаление оригинального файла после преобразования.
  echo "$filename.$SUFFIX"  # Вывод на stdout.
done

exit 0

# Упражнение:
# --------
#  Сейчас этот сценарий конвертирует *все* файлы в каталоге
#  Измените его так, чтобы он конвертировал *только* те файлы,
#+ которые имеют расширение ".mac".
</pre>
                  </div>
                </dd>
              </dl>
            </div>

            <div class="VARIABLELIST">
              <p><strong>Замена подстроки</strong></p>

              <dl>
                <dt>${string/substring/replacement}</dt>

                <dd>
                  <p>Замещает первое вхождение <code class="REPLACEABLE"><em>$substring</em></code> строкой
                  <code class="REPLACEABLE"><em>$replacement</em></code>.</p>
                </dd>

                <dt>${string//substring/replacement}</dt>

                <dd>
                  <p>Замещает все вхождения <code class="REPLACEABLE"><em>$substring</em></code> строкой
                  <code class="REPLACEABLE"><em>$replacement</em></code>.</p>
<pre class="PROGRAMLISTING">stringZ=abcABC123ABCabc

echo ${stringZ/abc/xyz}           # xyzABC123ABCabc
                                  # Замена первой подстроки 'abc' строкой 'xyz'.

echo ${stringZ//abc/xyz}          # xyzABC123ABCxyz
                                  # Замена всех подстрок 'abc' строкой 'xyz'.
</pre>
                  <br>
                  <br>
                </dd>

                <dt>${string/#substring/replacement}</dt>

                <dd>
                  <p>Подстановка строки <code class="REPLACEABLE"><em>$replacement</em></code>
                  вместо <code class="REPLACEABLE"><em>$substring</em></code>. Поиск
                  ведется с начала строки <code class="REPLACEABLE"><em>$string</em></code>.</p>
                </dd>

                <dt>${string/%substring/replacement}</dt>

                <dd>
                  <p>Подстановка строки <code class="REPLACEABLE"><em>$replacement</em></code>
                  вместо <code class="REPLACEABLE"><em>$substring</em></code>. Поиск
                  ведется с конца строки <code class="REPLACEABLE"><em>$string</em></code>.</p>
<pre class="PROGRAMLISTING">stringZ=abcABC123ABCabc

echo ${stringZ/#abc/XYZ}          # XYZABC123ABCabc
                                  # Поиск ведется с начала строки

echo ${stringZ/%abc/XYZ}          # abcABC123ABCXYZ
                                  # Поиск ведется с конца строки
</pre>
                  <br>
                  <br>
                </dd>
              </dl>
            </div>

            <div class="SECT2">
              <hr>

              <h3 class="SECT2"><a name="AWKSTRINGMANIP"></a>9.2.1. Использование awk при
              работе со строками</h3>

              <p>В качестве альтернативы, Bash-скрипты могут
              использовать средства <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AWKREF">awk</a> при работе со строками.</p>

              <div class="EXAMPLE">
                <a name="SUBSTRINGEX"></a>

                <p><strong>Пример 9-12. Альтернативный способ
                извлечения подстрок</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# substring-extraction.sh

String=23skidoo1
#      012345678    Bash
#      123456789    awk
# Обратите внимание на различия в индексации:
# Bash начинает индексацию с '0'.
# Awk  начинает индексацию с '1'.

echo ${String:2:4} # с 3 позиции (0-1-2), 4 символа
                   # skid

# В эквивалент в awk: substr(string,pos,length).
echo | awk '
{ print substr("'"${String}"'",3,4)      # skid
}
'
#  Передача пустого "echo" по каналу в awk, означает фиктивный ввод,
#+ делая, тем самым, ненужным предоставление имени файла.

exit 0
</pre>
              </div>
            </div>

            <div class="SECT2">
              <hr>

              <h3 class="SECT2"><a name="STRFDISC"></a>9.2.2. Дальнейшее обсуждение</h3>

              <p>Дополнительную информацию, по работе со строками, вы
              найдете в разделе <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PARAMETER-SUBSTITUTION">Section 9.3</a> и в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXPEXTRSUB">секции</a>, посвященной команде <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXPRREF">expr</a>. Примеры сценариев:</p>

              <ol type="1">
                <li>
                  <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX45">Пример 12-6</a></p>
                </li>

                <li>
                  <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LENGTH">Пример 9-15</a></p>
                </li>

                <li>
                  <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PATTMATCHING">Пример 9-16</a></p>
                </li>

                <li>
                  <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RFE">Пример 9-17</a></p>
                </li>

                <li>
                  <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#VARMATCH">Пример 9-19</a></p>
                </li>
              </ol>
              <br>
              <br>
            </div>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="PARAMETER-SUBSTITUTION"></a>9.3. Подстановка
            параметров</h2>

            <p><a name="PARAMSUBREF"></a></p>

            <div class="VARIABLELIST">
              <p><strong><a name="PSSUB1"></a>Работа с переменными и/или подстановка
              их значений</strong></p>

              <dl>
                <dt><code class="USERINPUT"><strong>${parameter}</strong></code></dt>

                <dd>
                  <p>То же самое, что и <code class="REPLACEABLE"><em>$parameter</em></code>, т.е.
                  значение переменной <code class="REPLACEABLE"><em>parameter</em></code>. В
                  отдельных случаях, при возникновении неоднозначности
                  интерпретации, корректно будет работать только такая
                  форма записи: <code class="REPLACEABLE"><em>${parameter}</em></code>.</p>

                  <p>Может использоваться для конкатенации (слияния)
                  строковых переменных.</p>
<pre class="PROGRAMLISTING">your_id=${USER}-on-${HOSTNAME}
echo "$your_id"
#
echo "Старый \$PATH = $PATH"
PATH=${PATH}:/opt/bin  #Добавление /opt/bin в $PATH.
echo "Новый \$PATH = $PATH"
</pre>
                  <br>
                  <br>
                </dd>

                <dt><code class="USERINPUT"><strong>${parameter-default}</strong></code>,
                <code class="USERINPUT"><strong>${parameter:-default}</strong></code></dt>

                <dd>
                  <p>Если параметр отсутствует, то используется
                  значение по-умолчанию.</p>
<pre class="PROGRAMLISTING">echo ${username-`whoami`}
# Вывод результата работы команды `whoami`, если переменная $username не установлена.
</pre>
                  <br>
                  <br>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p>Формы записи <code class="REPLACEABLE"><em>${parameter-default}</em></code>
                          и <code class="REPLACEABLE"><em>${parameter:-default}</em></code>
                          в большинстве случаев можно считать
                          эквивалентными. Дополнительный символ <span class="TOKEN">:</span> имеет значение только
                          тогда, когда <span class="emphasis"><em class="EMPHASIS">parameter</em></span>
                          определен, но имеет "пустое" (null)
                          значение.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
<pre class="PROGRAMLISTING">#!/bin/bash

username0=
# переменная username0 объявлена, но инициализирована "пустым" значением.
echo "username0 = ${username0-`whoami`}"
# Вывод после символа "=" отсутствует.

echo "username1 = ${username1-`whoami`}"
# Переменная username1 не была объявлена.
# Выводится имя пользователя, выданное командой `whoami`.

username2=
# переменная username2 объявлена, но инициализирована "пустым" значением.
echo "username2 = ${username2:-`whoami`}"
# Выводится имя пользователя, выданное командой `whoami`, поскольку
#+здесь употребляется конструкция ":-" , а не  "-".

exit 0
</pre>
                  <br>
                  <br>

                  <p><span class="emphasis"><em class="EMPHASIS">Параметры по-умолчанию</em></span>
                  очень часто находят применение в случаях, когда
                  сценарию необходимы какие либо входные аргументы,
                  передаваемые из командной строки, но такие аргументы
                  не были переданы.</p>
<pre class="PROGRAMLISTING">DEFAULT_FILENAME=generic.data
filename=${1:-$DEFAULT_FILENAME}
#  Если имя файла не задано явно, то последующие операторы будут работать
#+ с файлом "generic.data".
#
</pre>
                  <br>
                  <br>

                  <p>см. так же <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX58">Пример 3-4</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX73">Пример 28-2</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COLLATZ">Пример A-7</a>.</p>

                  <p>Сравните этот подход с <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ANDDEFAULT">методом списков <span class="emphasis"><em class="EMPHASIS">and list</em></span>, для задания
                  параметров командной строки по-умолчанию</a> .</p>
                </dd>

                <dt><code class="USERINPUT"><strong>${parameter=default}</strong></code>,
                <code class="USERINPUT"><strong>${parameter:=default}</strong></code></dt>

                <dd>
                  <p><a name="DEFPARAM"></a></p>

                  <p>Если значения параметров не задананы явно, то они
                  принимают значения по-умолчанию.</p>

                  <p>Оба метода задания значений по-умолчанию до
                  определенной степени идентичны. Символ <span class="TOKEN">:</span> имеет значение только когда
                  <span class="emphasis"><em class="EMPHASIS">$parameter</em></span> был
                  инициализирован "пустым" (null) значением,
                  <a name="AEN4520" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN4520"><span class="footnote">[22]</span></a> как показано
                  выше.</p>
<pre class="PROGRAMLISTING">echo ${username=`whoami`}
# Переменная "username" принимает значение, возвращаемое командой `whoami`.
</pre>
                  <br>
                  <br>
                </dd>

                <dt><code class="USERINPUT"><strong>${parameter+alt_value}</strong></code>,
                <code class="USERINPUT"><strong>${parameter:+alt_value}</strong></code></dt>

                <dd>
                  <p>Если параметр имеет какое либо значение, то
                  используется <code class="USERINPUT"><strong>alt_value</strong></code>,
                  иначе -- null ("пустая" строка).</p>

                  <p>Оба варианта до определенной степени идентичны.
                  Символ <span class="TOKEN">:</span> имеет значение только если
                  <span class="emphasis"><em class="EMPHASIS">parameter</em></span> объявлен и
                  "пустой", см. ниже.</p>
<pre class="PROGRAMLISTING">echo "###### \${parameter+alt_value} ########"
echo

a=${param1+xyz}
echo "a = $a"      # a =

param2=
a=${param2+xyz}
echo "a = $a"      # a = xyz

param3=123
a=${param3+xyz}
echo "a = $a"      # a = xyz

echo
echo "###### \${parameter:+alt_value} ########"
echo

a=${param4:+xyz}
echo "a = $a"      # a =

param5=
a=${param5:+xyz}
echo "a = $a"      # a =
# Вывод отличается от a=${param5+xyz}

param6=123
a=${param6+xyz}
echo "a = $a"      # a = xyz
</pre>
                  <br>
                  <br>
                </dd>

                <dt><a name="QERRMSG"></a><code class="USERINPUT"><strong>${parameter?err_msg}</strong></code>,
                <code class="USERINPUT"><strong>${parameter:?err_msg}</strong></code></dt>

                <dd>
                  <p>Если parameter инициализирован, то используется
                  его значение, в противном случае -- выводится
                  err_msg.</p>

                  <p>Обе формы записи можно, до определенной степени,
                  считать идентичными. Символ <span class="TOKEN">:</span> имеет значение только когда
                  <span class="emphasis"><em class="EMPHASIS">parameter</em></span>
                  инициализирован "пустым" значением, см.
                  ниже.</p>
                </dd>
              </dl>
            </div>

            <div class="EXAMPLE">
              <a name="EX6"></a>

              <p><strong>Пример 9-13. Подстановка параметров и
              сообщения об ошибках</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

#  Проверка отдельных переменных окружения.
#  Если переменная, к примеру $USER, не установлена,
#+ то выводится сообщение об ошибке.

: ${HOSTNAME?} ${USER?} ${HOME?} ${MAIL?}
  echo
  echo "Имя машины: $HOSTNAME."
  echo "Ваше имя: $USER."
  echo "Ваш домашний каталог: $HOME."
  echo "Ваш почтовый ящик: $MAIL."
  echo
  echo "Если перед Вами появилось это сообщение,"
  echo "то это значит, что все критические переменные окружения установлены."
  echo
  echo

# ------------------------------------------------------

#  Конструкция ${variablename?} так же выполняет проверку
#+ наличия переменной в сценарии.

ThisVariable=Value-of-ThisVariable
#  Обратите внимание, в строковые переменные могут быть записаны
#+ символы, которые запрещено использовать в именах переменных.
: ${ThisVariable?}
echo "Value of ThisVariable is $ThisVariable".
echo
echo


: ${ZZXy23AB?"Переменная ZZXy23AB не инициализирована."}
#  Если ZZXy23AB не инициализирована,
#+ то сценарий завершается с сообщением об ошибке.

# Текст сообщения об ошибке можно задать свой.
# : ${ZZXy23AB?"Переменная ZZXy23AB не инициализирована."}


# То же самое:  dummy_variable=${ZZXy23AB?}
#               dummy_variable=${ZZXy23AB?"Переменная ZXy23AB не инициализирована."}
#
#               echo ${ZZXy23AB?} &gt;/dev/null



echo "Это сообщение не будет напечатано, поскольку сценарий завершится раньше."

HERE=0
exit $HERE   # Сценарий завершит работу не здесь.
</pre>
            </div>

            <div class="EXAMPLE">
              <a name="USAGEMESSAGE"></a>

              <p><strong>Пример 9-14. Подстановка параметров и
              сообщение о <span class="QUOTE">"порядке
              использования"</span></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# usage-message.sh

: ${1?"Порядок использования: $0 ARGUMENT"}
#  Сценарий завершит свою работу здесь, если входные аргументы отсутствуют,
#+ со следующим сообщением.
#    usage-message.sh: 1: Порядок использования: usage-message.sh ARGUMENT

echo "Эти две строки появятся, только когда задан аргумент в командной строке."
echo "Входной аргумент командной строки = \"$1\""

exit 0 # Точка выхода находится здесь, только когда задан аргумент командной строки.

# Проверьте код возврата в обеих случаях, с и без аргумента командной строки.
# Если аргумент задан, то код возврата будет равен 0.
# Иначе -- 1.
</pre>
            </div>

            <div class="FORMALPARA">
              <p><strong>Подстановка параметров и/или
              экспансия.</strong> <a name="PSUB2"></a>Следующие выражения могут служить
              дополнениями оператора <strong class="COMMAND">match</strong> команды <strong class="COMMAND">expr</strong>, применяемой к строкам
              (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX45">Пример 12-6</a>). Как правило, они
              используются при разборе имен файлов и каталогов.</p>
            </div>

            <div class="VARIABLELIST">
              <p><strong><a name="PSOREX1"></a>Длина переменной / Удаление
              подстроки</strong></p>

              <dl>
                <dt><code class="USERINPUT"><strong>${#var}</strong></code></dt>

                <dd>
                  <p><code class="USERINPUT"><strong>String
                  length</strong></code> (число символов в переменной <code class="VARNAME">$var</code>). В случае <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ARRAYREF">массивов</a>, команда <strong class="COMMAND">${#array}</strong> возвращает длину
                  первого элемента массива.</p>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p>Исключения:</p>

                          <ul>
                            <li>
                              <p><strong class="COMMAND">${#*}</strong> и <strong class="COMMAND">${#@}</strong>
                              возвращает <span class="emphasis"><em class="EMPHASIS">количество аргументов
                              (позиционных параметров)</em></span>.</p>
                            </li>

                            <li>
                              <p>Для массивов, <strong class="COMMAND">${#array[*]}</strong> и
                              <strong class="COMMAND">${#array[@]}</strong>
                              возвращает количество элементов в
                              массиве.</p>
                            </li>
                          </ul>
                          <br>
                          <br>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>

                  <div class="EXAMPLE">
                    <a name="LENGTH"></a>

                    <p><strong>Пример 9-15. Длина
                    переменной</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# length.sh

E_NO_ARGS=65

if [ $# -eq 0 ]  # Для работы скрипта необходим хотя бы один входной параметр.
then
  echo "Вызовите сценарий с одним или более параметром командной строки."
  exit $E_NO_ARGS
fi

var01=abcdEFGH28ij

echo "var01 = ${var01}"
echo "Length of var01 = ${#var01}"

echo "Количество входных параметров = ${#@}"
echo "Количество входных параметров = ${#*}"

exit 0
</pre>
                  </div>
                </dd>

                <dt><code class="USERINPUT"><strong>${var#Pattern}</strong></code>, <code class="USERINPUT"><strong>${var##Pattern}</strong></code></dt>

                <dd>
                  <p>Удаляет из переменной <code class="VARNAME">$var</code> наименьшую/наибольшую
                  подстроку, совпадающую с шаблоном <code class="VARNAME">$Pattern</code>. Поиск ведется с
                  начала строки <code class="VARNAME">$var</code>.</p>

                  <p>Пример использования из <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DAYSBETWEEN">Пример A-8</a>:</p>
<pre class="PROGRAMLISTING"># Функцмя из сценария "days-between.sh".
# Удаляет нули, стоящие в начале аргумента-строки.

strip_leading_zero () # Ведущие нули, которые согут находиться в номере дня/месяца,
                      # лучше удалить
  val=${1#0}          # В противном случае Bash будет интерпретировать числа
  return $val         # как восьмеричные (POSIX.2, sect 2.9.2.1).
}
</pre>
                  <br>
                  <br>

                  <p>Другой пример:</p>
<pre class="PROGRAMLISTING">echo `basename $PWD`        # Имя текущего рабочего каталога.
echo "${PWD##*/}"           # Имя текущего рабочего каталога.
echo
echo `basename $0`          # Имя файла-сценария.
echo $0                     # Имя файла-сценария.
echo "${0##*/}"             # Имя файла-сценария.
echo
filename=test.data
echo "${filename##*.}"      # data
                            # Расширение файла.
</pre>
                  <br>
                  <br>
                </dd>

                <dt><a name="PCTPATREF"></a><code class="USERINPUT"><strong>${var%Pattern}</strong></code>, <code class="USERINPUT"><strong>${var%%Pattern}</strong></code></dt>

                <dd>
                  <p>Удаляет из переменной <code class="VARNAME">$var</code> наименьшую/наибольшую
                  подстроку, совпадающую с шаблоном <code class="VARNAME">$Pattern</code>. Поиск ведется с конца
                  строки <code class="VARNAME">$var</code>.</p>
                </dd>
              </dl>
            </div>

            <p>Bash <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BASH2REF">версии 2</a> имеет ряд дополнительных
            возможностей.</p>

            <div class="EXAMPLE">
              <a name="PATTMATCHING"></a>

              <p><strong>Пример 9-16. Поиск по шаблону в подстановке
              параметров</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Поиск по шаблону в операциях подстановки параметров # ## % %%.

var1=abcd12345abc6789
pattern1=a*c  # * (символ шаблона), означает любые символы между a и c.

echo
echo "var1 = $var1"           # abcd12345abc6789
echo "var1 = ${var1}"         # abcd12345abc6789   (альтернативный вариант)
echo "Число символов в ${var1} = ${#var1}"
echo "pattern1 = $pattern1"   # a*c  (между 'a' и 'c' могут быть любые символы)
echo


echo '${var1#$pattern1}  =' "${var1#$pattern1}"    #         d12345abc6789
# Наименьшая подстрока, удаляются первые 3 символа  abcd12345abc6789
                                  ^^^^^^            |-|
echo '${var1##$pattern1} =' "${var1##$pattern1}"   #                  6789
# Наибольшая подстрока, удаляются первые 12 символов abcd12345abc6789
#                                 ^^^^^^             |----------|

echo; echo

pattern2=b*9            # все, что между 'b' и '9'
echo "var1 = $var1"     # abcd12345abc6789
echo "pattern2 = $pattern2"
echo

echo '${var1%pattern2}  =' "${var1%$pattern2}"     #     abcd12345a
# Наименьшая подстрока, удаляются последние 6 символов  abcd12345abc6789
#                                 ^^^^^^^^^                       |----|
echo '${var1%%pattern2} =' "${var1%%$pattern2}"    #     a
# Наибольшая подстрока, удаляются последние 12 символов  abcd12345abc6789
#                                 ^^^^^^^^^               |-------------|

# Запомните, # и ## используются для поиска с начала строки,
#            % и %% используются для поиска с конца строки.

echo

exit 0
</pre>
            </div>

            <div class="EXAMPLE">
              <a name="RFE"></a>

              <p><strong>Пример 9-17. Изменение расширений в именах
              файлов<span class="TOKEN">:</span></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

#                 rfe
#                 ---

# Изменение расширений в именах файлов.
#
#         rfe old_extension new_extension
#
# Пример:
# Изменить все расширения *.gif в именах файлов на *.jpg, в текущем каталоге
#          rfe gif jpg

ARGS=2
E_BADARGS=65

if [ $# -ne "$ARGS" ]
then
  echo "Порядок использования: `basename $0` old_file_suffix new_file_suffix"
  exit $E_BADARGS
fi

for filename in *.$1
# Цикл прохода по списку имен файлов, имеющих расширение равное первому аргументу.
do
  mv $filename ${filename%$1}$2
  #  Удалить первое расширение и добавить второе,
done

exit 0
</pre>
            </div>

            <div class="VARIABLELIST">
              <p><strong><a name="EXPREPL1"></a>Подстановка значений переменных /
              Замена подстроки</strong></p>

              <dl>
                <dd>
                  <p>Эти конструкции перекочевали в Bash из <span class="emphasis"><em class="EMPHASIS">ksh</em></span>.</p>
                </dd>

                <dt><code class="USERINPUT"><strong>${var:pos}</strong></code></dt>

                <dd>
                  <p>Подстанавливается значение переменной <code class="REPLACEABLE"><em>var</em></code>, начиная с
                  позиции <code class="REPLACEABLE"><em>pos</em></code>.</p>
                </dd>

                <dt><code class="USERINPUT"><strong>${var:pos:len}</strong></code></dt>

                <dd>
                  <p>Подстанавливается значение переменной <code class="REPLACEABLE"><em>var</em></code>, начиная с
                  позиции <code class="REPLACEABLE"><em>pos</em></code>, не более <code class="REPLACEABLE"><em>len</em></code> символов. См.
                  <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PW">Пример A-16</a>.</p>
                </dd>

                <dt><code class="USERINPUT"><strong>${var/Pattern/Replacement}</strong></code></dt>

                <dd>
                  <p>Первое совпадение с шаблоном <code class="REPLACEABLE"><em>Pattern</em></code>, в
                  переменной <code class="REPLACEABLE"><em>var</em></code> замещается
                  подстрокой <code class="REPLACEABLE"><em>Replacement</em></code>.</p>

                  <p>Если подстрока <code class="REPLACEABLE"><em>Replacement</em></code>
                  отсутствует, то найденное совпадение будет
                  удалено.</p>
                </dd>

                <dt><code class="USERINPUT"><strong>${var//Pattern/Replacement}</strong></code></dt>

                <dd>
                  <div class="FORMALPARA">
                    <p><strong>Глобальная замена.</strong> Все
                    найденные совпадения с шаблоном <code class="REPLACEABLE"><em>Pattern</em></code>, в
                    переменной <code class="REPLACEABLE"><em>var</em></code>, будут
                    замещены подстрокой <code class="REPLACEABLE"><em>Replacement</em></code>.</p>
                  </div>

                  <p>Как и в первом случае, если подстрока <code class="REPLACEABLE"><em>Replacement</em></code>
                  отсутствует, то все найденные совпадения будут
                  удалены.</p>

                  <div class="EXAMPLE">
                    <a name="EX7"></a>

                    <p><strong>Пример 9-18. Поиск по шаблону при
                    анализе произвольных строк</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

var1=abcd-1234-defg
echo "var1 = $var1"

t=${var1#*-*}
echo "var1 (все, от начала строки по первый символ \"-\", включительно, удаляется) = $t"
#  t=${var1#*-}  то же самое,
#+ поскольку оператор # ищет кратчайшее совпадение,
#+ а * соответствует любым предшествующим символам, включая пустую строку.
# (Спасибо S. C. за разъяснения.)

t=${var1##*-*}
echo "Если var1 содержит \"-\", то возвращается пустая строка...   var1 = $t"


t=${var1%*-*}
echo "var1 (все, начиная с последнего \"-\" удаляется) = $t"

echo

# -------------------------------------------
path_name=/home/bozo/ideas/thoughts.for.today
# -------------------------------------------
echo "path_name = $path_name"
t=${path_name##/*/}
echo "Из path_name удален путь к файлу = $t"
#  В данном случае, тот эе эффект можно получить так:  t=`basename $path_name`
#  t=${path_name%/}; t=${t##*/}   более общее решение,
#+ но имеет некоторые ограничения.
#  Если $path_name заканчивается символом перевода строки, то `basename $path_name` не будет работать,
#+ но для данного случая вполне применимо.
# (Спасибо S.C.)

t=${path_name%/*.*}
# Тот же эффект дает    t=`dirname $path_name`
echo "Из path_name удалено имя файла = $t"
# Этот вариант будет терпеть неудачу в случаях: "../", "/foo////", # "foo/", "/".
#  Удаление имени файла, особенно когда его нет,
#+ использование dirname имеет свои особенности.
# (Спасибо S.C.)

echo

t=${path_name:11}
echo "Из $path_name удалены первые 11 символов = $t"
t=${path_name:11:5}
echo "Из $path_name удалены первые 11 символов, выводится 5 символов = $t"

echo

t=${path_name/bozo/clown}
echo "В $path_name подстрока \"bozo\" заменена на \"clown\" = $t"
t=${path_name/today/}
echo "В $path_name подстрока \"today\" удалена = $t"
t=${path_name//o/O}
echo "В $path_name все символы \"o\" переведены в верхний регистр, = $t"
t=${path_name//o/}
echo "Из $path_name удалены все символы \"o\" = $t"

exit 0
</pre>
                  </div>
                </dd>

                <dt><code class="USERINPUT"><strong>${var/#Pattern/Replacement}</strong></code></dt>

                <dd>
                  <p>Если в переменной <code class="REPLACEABLE"><em>var</em></code> найдено
                  совпадение с <code class="REPLACEABLE"><em>Pattern</em></code>, причем
                  совпадающая подстрока расположена в начале строки
                  (префикс), то оно заменяется на <code class="REPLACEABLE"><em>Replacement</em></code>. Поиск
                  ведется с начала строки</p>
                </dd>

                <dt><code class="USERINPUT"><strong>${var/%Pattern/Replacement}</strong></code></dt>

                <dd>
                  <p>Если в переменной <code class="REPLACEABLE"><em>var</em></code> найдено
                  совпадение с <code class="REPLACEABLE"><em>Pattern</em></code>, причем
                  совпадающая подстрока расположена в конце строки
                  (суффикс), то оно заменяется на <code class="REPLACEABLE"><em>Replacement</em></code>. Поиск
                  ведется с конца строки</p>

                  <div class="EXAMPLE">
                    <a name="VARMATCH"></a>

                    <p><strong>Пример 9-19. Поиск префиксов и суффиксов
                    с заменой по шаблону</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Поиск с заменой по шаблону.

v0=abc1234zip1234abc    # Начальное значение переменной.
echo "v0 = $v0"         # abc1234zip1234abc
echo

# Поиск совпадения с начала строки.
v1=${v0/#abc/ABCDEF}    # abc1234zip1234abc
                        # |-|
echo "v1 = $v1"         # ABCDE1234zip1234abc
                        # |---|

# Поиск совпадения с конца строки.
v2=${v0/%abc/ABCDEF}    # abc1234zip123abc
                        #              |-|
echo "v2 = $v2"         # abc1234zip1234ABCDEF
                        #               |----|

echo

#  ----------------------------------------------------
#  Если совпадение находится не с начала/конца строки,
#+ то замена не производится.
#  ----------------------------------------------------
v3=${v0/#123/000}       # Совпадение есть, но не в начале строки.
echo "v3 = $v3"         # abc1234zip1234abc
                        # ЗАМЕНА НЕ ПРОИЗВОДТСЯ!
v4=${v0/%123/000}       # Совпадение есть, но не в конце строки.
echo "v4 = $v4"         # abc1234zip1234abc
                        # ЗАМЕНА НЕ ПРОИЗВОДТСЯ!

exit 0
</pre>
                  </div>
                </dd>

                <dt><code class="USERINPUT"><strong>${!varprefix*}</strong></code>, <code class="USERINPUT"><strong>${!varprefix@}</strong></code></dt>

                <dd>
                  <p>Поиск по шаблону всех, ранее объявленных
                  переменных, имена которых начинаются с <span class="emphasis"><em class="EMPHASIS">varprefix</em></span>.</p>
<pre class="PROGRAMLISTING">xyz23=whatever
xyz24=

a=${!xyz*}      # Подстановка имен объявленных переменных, которые начинаются с "xyz".
echo "a = $a"   # a = xyz23 xyz24
a=${!xyz@}      # То же самое.
echo "a = $a"   # a = xyz23 xyz24

# Эта возможность была добавлена в Bash, в версии 2.04.
</pre>
                  <br>
                  <br>
                </dd>
              </dl>
            </div>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="DECLAREREF"></a>9.4. Объявление переменных: <strong class="COMMAND">declare</strong> и <strong class="COMMAND">typeset</strong></h2>

            <p>Инструкции <strong class="COMMAND">declare</strong> и <strong class="COMMAND">typeset</strong> являются <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BUILTINREF">встроенными</a> инструкциями (они
            абсолютно идентичны друг другу и являются синонимами) и
            предназначена для наложения ограничений на переменные. Это
            очень слабая попытка контроля над типами, которая имеется
            во многих языках программирования. Инструкция <strong class="COMMAND">declare</strong> появилась в Bash, начиная
            с версии 2. Кроме того, инструкция <strong class="COMMAND">typeset</strong> может использоваться и в
            ksh-сценариях.</p>

            <div class="VARIABLELIST">
              <p><strong><a name="DECLAREOPSREF1"></a>ключи инструкций
              declare/typeset</strong></p>

              <dl>
                <dt><span class="TOKEN">-r</span> <code class="REPLACEABLE"><em>readonly</em></code> (только для
                чтения)</dt>

                <dd>
<pre class="PROGRAMLISTING">declare -r var1
</pre>
                  <br>
                  <br>

                  <p>(<code class="USERINPUT"><strong>declare -r
                  var1</strong></code> аналогично объявлению <code class="USERINPUT"><strong>readonly
                  var1</strong></code>)</p>

                  <p>Это грубый эквивалент констант (const) в языке C.
                  Попытка изменения таких переменных завершается
                  сообщением об ошибке.</p>
                </dd>

                <dt><span class="TOKEN">-i</span> <code class="REPLACEABLE"><em>integer</em></code></dt>

                <dd>
<pre class="PROGRAMLISTING">declare -i number
# Сценарий интерпретирует переменную "number" как целое число.

number=3
echo "number = $number"     # number = 3

number=three
echo "number = $number"     # number = 0
# Строка "three" интерпретируется как целое число.
</pre>
                  Примечательно, что допускается выполнение некоторых
                  арифметических операций над переменными, объявленными
                  как integer, не прибегая к инструкциям <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXPRREF">expr</a> или <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LETREF">let</a>.<br>
                  <br>
                </dd>

                <dt><span class="TOKEN">-a</span> <code class="REPLACEABLE"><em>array</em></code></dt>

                <dd>
<pre class="PROGRAMLISTING">declare -a indices
</pre>
                  <br>
                  <br>

                  <p>Переменная <code class="VARNAME">indices</code> объявляется
                  массивом.</p>
                </dd>

                <dt><span class="TOKEN">-f</span> <code class="REPLACEABLE"><em>functions</em></code></dt>

                <dd>
<pre class="PROGRAMLISTING">declare -f
</pre>
                  <br>
                  <br>

                  <p>Инструкция <code class="USERINPUT"><strong>declare -f</strong></code>,
                  без аргументов, приводит к выводу списка ранее
                  объявленных функций в сценарии.</p>
<pre class="PROGRAMLISTING">declare -f function_name
</pre>
                  <br>
                  <br>

                  <p>Инструкция <code class="USERINPUT"><strong>declare -f
                  function_name</strong></code> выводит имя функции
                  function_name, если она была объявлена ранее.</p>
                </dd>

                <dt><span class="TOKEN">-x</span> <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXPORTREF">export</a></dt>

                <dd>
<pre class="PROGRAMLISTING">declare -x var3
</pre>
                  <br>
                  <br>

                  <p>Эта инструкция объявляет переменную, как доступную
                  для экспорта.</p>
                </dd>

                <dt>var=$value</dt>

                <dd>
<pre class="PROGRAMLISTING">declare -x var3=373
</pre>
                  <br>
                  <br>

                  <p>Инструкция <strong class="COMMAND">declare</strong> допускает
                  совмещение объявления и присваивания значения
                  переменной одновременно.</p>
                </dd>
              </dl>
            </div>

            <div class="EXAMPLE">
              <a name="EX20"></a>

              <p><strong>Пример 9-20. Объявление переменных с помощью
              инструкции declare</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

func1 ()
{
echo Это функция.
}

declare -f        # Список функций, объявленных выше.

echo

declare -i var1   # var1 -- целочисленная переменная.
var1=2367
echo "переменная var1 объявлена как $var1"
var1=var1+1       # Допустимая арифметическая операция над целочисленными переменными.
echo "переменная var1 увеличена на 1 = $var1."
# Допустимая операция для целочисленных переменных
echo "Возможно ли записать дробное число 2367.1 в var1?"
var1=2367.1       # Сообщение об ошибке, переменная не изменяется.
echo "значение переменной var1 осталось прежним = $var1"

echo

declare -r var2=13.36         # инструкция 'declare' допускает установку свойств переменной
                              #+ и одновременно присваивать значение.
echo "var2 declared as $var2" # Допускается ли изменять значение readonly переменных?
var2=13.37                    # Сообщение об ошибке и завершение работы сценария.

echo "значение переменной var2 осталось прежним $var2" # Эта строка никогда не будет выполнена.

exit 0                        # Сценарий завершит работу выше.
</pre>
            </div>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="IVR"></a>9.5. Косвенные ссылки на переменные</h2>

            <p><a name="IVRREF"></a></p>

            <p>Предположим, что значение одной переменной -- есть имя
            второй переменной. Возможно ли получить значение второй
            переменной через обращение к первой? Например, Пусть <code class="REPLACEABLE"><em>a=letter_of_alphabet</em></code> и
            <code class="REPLACEABLE"><em>letter_of_alphabet=z</em></code>,
            тогда вопрос будет звучать так: "Возможно ли получить
            значение <code class="REPLACEABLE"><em>z</em></code>, обратившись к
            переменной <code class="REPLACEABLE"><em>a</em></code>?". В
            действительности это возможно и это называется <span class="emphasis"><em class="EMPHASIS">косвенной ссылкой</em></span>. Для этого
            необходимо прибегнуть к несколько необычной нотации <code class="REPLACEABLE"><em>eval var1=\$$var2</em></code>.</p>

            <div class="EXAMPLE">
              <a name="INDREF"></a>

              <p><strong>Пример 9-21. Косвенные ссылки</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Косвенные ссылки на переменные.

a=letter_of_alphabet
letter_of_alphabet=z

echo

# Прямое обращение к переменной.
echo "a = $a"

# Косвенное обращение к переменной.
eval a=\$$a
echo "А теперь a = $a"

echo


# Теперь попробуем изменить переменную, на которую делается ссылка.

t=table_cell_3
table_cell_3=24
echo "\"table_cell_3\" = $table_cell_3"
echo -n "разыменование (получение ссылки) \"t\" = "; eval echo \$$t
# В данном, простом, случае,
#   eval t=\$$t; echo "\"t\" = $t"
# дает тот же результат (почему?).

echo

t=table_cell_3
NEW_VAL=387
table_cell_3=$NEW_VAL
echo "Значение переменной \"table_cell_3\" изменено на $NEW_VAL."
echo "Теперь \"table_cell_3\" = $table_cell_3"
echo -n "разыменование (получение ссылки) \"t\" = "; eval echo \$$t
# инструкция "eval" принимает два аргумента "echo" и "\$$t" (назначает равным $table_cell_3)
echo

# (Спасибо S.C. за разъяснения.)


# Еще один способ -- нотация ${!t}, будет обсуждаться в разделе "Bash, версия 2".
# Так же, см. пример "ex78.sh".

exit 0
</pre>
            </div>

            <div class="EXAMPLE">
              <a name="COLTOTALER2"></a>

              <p><strong>Пример 9-22. Передача косвенных ссылок в <code class="REPLACEABLE"><em>awk</em></code></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# Другая версия сценария "column totaler"
# который суммирует заданную колонку (чисел) в заданном файле.
# Здесь используются косвенные ссылки.

ARGS=2
E_WRONGARGS=65

if [ $# -ne "$ARGS" ] # Проверка количества входных аргументов.
then
   echo "Порядок использования: `basename $0` filename column-number"
   exit $E_WRONGARGS
fi

filename=$1
column_number=$2

#===== До этой строки идентично первоначальному варианту сценария =====#


# Мнгострочные скрипты awk вызываются конструкцией   awk ' ..... '


# Начало awk-сценария.
# ------------------------------------------------
awk "

{ total += \$${column_number} # косвенная ссылка
}
END {
     print total
     }

     " "$filename"
# ------------------------------------------------
# Конец awk-сценария.

# Косвенные ссылки делают возможным бесконфликтное
# обращение к переменным shell внутри вложенных сценариев awk.
# Спасибо Stephane Chazelas.


exit 0
</pre>
            </div>

            <div class="CAUTION">
              <table class="CAUTION" width="100%" border="0">
                <tbody><tr>
                  <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                  <td align="left" valign="top">
                    <p>Такой метод обращения к переменным имеет свои
                    особенности. Если переменная, на которую делается
                    ссылка, меняет свое значение, то переменная которая
                    ссылается, должна быть должным образом
                    разыменована, т.е. олжна быть выполнена операция
                    получения ссылки, как это делается в примере выше.
                    <a name="IVR2"></a>К счастью, нотация <code class="REPLACEABLE"><em>${!variable}</em></code>,
                    введенная в Bash, начиная с <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BASH2REF">версии 2</a> (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX78">Пример 34-2</a>) позволяет выполнять
                    косвенные ссылки более интуитивно понятным
                    образом.</p>
                  </td>
                </tr>
              </tbody></table>
            </div>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="RANDOMVAR"></a>9.6. $RANDOM: генерация
            псевдослучайных целых чисел</h2>

            <p>$RANDOM -- внутренняя функция Bash (не константа),
            которая возвращает <span class="emphasis"><em class="EMPHASIS">псевдослучайные</em></span> целые числа в
            диапазоне 0 - 32767. Функция $RANDOM <code class="REPLACEABLE"><em>не</em></code> должна использоваться
            для генераци ключей шифрования.</p>

            <div class="EXAMPLE">
              <a name="EX21"></a>

              <p><strong>Пример 9-23. Генерация случайных
              чисел</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# $RANDOM возвращает различные случайные числа при каждом обращении к ней.
# Диапазон изменения: 0 - 32767 (16-битовое целое со знаком).

MAXCOUNT=10
count=1

echo
echo "$MAXCOUNT случайных чисел:"
echo "-----------------"
while [ "$count" -le $MAXCOUNT ]      # Генерация 10 ($MAXCOUNT) случайных чисел.
do
  number=$RANDOM
  echo $number
  let "count += 1"  # Нарастить счетчик.
done
echo "-----------------"

# Если вам нужны случайные числа не превышающие определенного числа,
# воспользуйтесь оператором деления по модулю (остаток от деления).

RANGE=500

echo

number=$RANDOM
let "number %= $RANGE"
echo "Случайное число меньше $RANGE  ---  $number"

echo

# Если вы желаете ограничить диапазон "снизу",
# то просто производите генерацию псевдослучайных чисел в цикле до тех пор,
# пока не получите число большее нижней границы.

FLOOR=200

number=0   # инициализация
while [ "$number" -le $FLOOR ]
do
  number=$RANDOM
done
echo "Случайное число, большее $FLOOR ---  $number"
echo


# Эти два способа могут быть скомбинированы.
number=0   #initialize
while [ "$number" -le $FLOOR ]
do
  number=$RANDOM
  let "number %= $RANGE"  # Ограничение "сверху" числом $RANGE.
done
echo "Случайное число в диапазоне от $FLOOR до $RANGE ---  $number"
echo


# Генерация случайных "true" и "false" значений.
BINARY=2
number=$RANDOM
T=1

let "number %= $BINARY"
# let "number &gt;&gt;= 14"    дает более равномерное распределение
# (сдвиг вправо смещает старший бит на нулевую позицию, остальные биты обнуляются).
if [ "$number" -eq $T ]
then
  echo "TRUE"
else
  echo "FALSE"
fi

echo


# Можно имитировать бросание 2-х игровых кубиков.
SPOTS=7   # остаток от деления на 7 дает диапазон 0 - 6.
ZERO=0
die1=0
die2=0

# Кубики "выбрасываются" раздельно.

  while [ "$die1" -eq $ZERO ]     # Пока на "кубике" ноль.
  do
    let "die1 = $RANDOM % $SPOTS" # Имитировать бросок первого кубика.
  done

  while [ "$die2" -eq $ZERO ]
  do
    let "die2 = $RANDOM % $SPOTS" # Имитировать бросок второго кубика.
  done

let "throw = $die1 + $die2"
echo "Результат броска кубиков = $throw"
echo


exit 0
</pre>
            </div>

            <div class="EXAMPLE">
              <a name="PICKCARD"></a>

              <p><strong>Пример 9-24. Выбор случайной карты из
              колоды</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# pick-card.sh

# Пример выбора случайного элемента массива.


# Выбор случайной карты из колоды.

Suites="Треф
Бубей
Червей
Пик"

Denominations="2
3
4
5
6
7
8
9
10
Валет
Дама
Король
Туз"

suite=($Suites)                # Инициализация массивов.
denomination=($Denominations)

num_suites=${#suite[*]}        # Количество элементов массивов.
num_denominations=${#denomination[*]}

echo -n "${denomination[$((RANDOM%num_denominations))]} "
echo ${suite[$((RANDOM%num_suites))]}


# $bozo sh pick-cards.sh
# Валет Треф


# Спасибо "jipe," за пояснения по работе с $RANDOM.
exit 0
</pre>
            </div>

            <div class="NOTE">
              <table class="NOTE" width="100%" border="0">
                <tbody><tr>
                  <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                  <td align="left" valign="top">
                    <p><span class="emphasis"><em class="EMPHASIS">Jipe</em></span> подсказал еще
                    один способ генерации случайных чисел из заданного
                    диапазона.</p>
<pre class="PROGRAMLISTING">#  Генерация случайных чисел в диапазоне 6 - 30.
rnumber=$((RANDOM%25+6))

#  Генерируется случайное число из диапазона 6 - 30,
#+ но при этом число должно делиться на 3 без остатка.
rnumber=$(((RANDOM%30/3+1)*3))

#  Упражнение: Попробуйте разобраться с выражением самостоятельно.
</pre>
                    <br>
                    <br>
                  </td>
                </tr>
              </tbody></table>
            </div>

            <p>Насколько случайны числа, возвращаемые функцией $RANDOM?
            Лучший способ оценить "случайность" генерируемых
            чисел -- это написать сценарий, который будет имитировать
            бросание игрального кубика достаточно большое число раз, а
            затем выведет количество выпадений каждой из граней...</p>

            <div class="EXAMPLE">
              <a name="RANDOMTEST"></a>

              <p><strong>Пример 9-25. Имитация бросания кубика с
              помощью RANDOM</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Случайные ли числа возвращает RANDOM?

RANDOM=$$       # Инициализация генератора случайных чисел числом PID процесса-сценария.

PIPS=6          # Кубик имеет 6 граней.
MAXTHROWS=600   # Можете увеличить, если не знаете куда девать свое время.
throw=0         # Счетчик бросков.

zeroes=0        # Обнулить счетчики выпадения отдельных граней.
ones=0          # т.к. неинициализированные переменные - "пустые", и не равны нулю!.
twos=0
threes=0
fours=0
fives=0
sixes=0

print_result ()
{
echo
echo "единиц   =   $ones"
echo "двоек    =   $twos"
echo "троек    =   $threes"
echo "четверок =   $fours"
echo "пятерок  =   $fives"
echo "шестерок =   $sixes"
echo
}

update_count()
{
case "$1" in
  0) let "ones += 1";;   # 0 соответствует грани "1".
  1) let "twos += 1";;   # 1 соответствует грани "2", и так далее
  2) let "threes += 1";;
  3) let "fours += 1";;
  4) let "fives += 1";;
  5) let "sixes += 1";;
esac
}

echo


while [ "$throw" -lt "$MAXTHROWS" ]
do
  let "die1 = RANDOM % $PIPS"
  update_count $die1
  let "throw += 1"
done

print_result

# Количество выпадений каждой из граней должно быть примерно одинаковым, если считать RANDOM достаточно случайным.
# Для $MAXTHROWS = 600, каждая грань должна выпасть примерно 100 раз (плюс-минус 20).
#
# Имейте ввиду, что RANDOM - это генератор ПСЕВДОСЛУЧАЙНЫХ чисел,

# Упражнение:
# ---------------
# Перепишите этот сценарий так, чтобы он имитировал 1000 бросков монеты.
# На каждом броске возможен один из двух вариантов выпадения - "ОРЕЛ" или "РЕШКА".

exit 0
</pre>
            </div>

            <p>Как видно из последнего примера, неплохо было бы
            производить переустановку начального числа генератора
            случайных чисел <code class="VARNAME">RANDOM</code> перед тем, как начать работу с
            ним. Если используется одно и то же начальное число, то
            генератор <code class="VARNAME">RANDOM</code> будет выдавать одну и ту же
            последовательность чисел. (Это совпадает с поведением
            функции <code class="REPLACEABLE"><em>random()</em></code> в языке C.)</p>

            <div class="EXAMPLE">
              <a name="SEEDINGRANDOM"></a>

              <p><strong>Пример 9-26. Переустановка RANDOM</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# seeding-random.sh: Переустановка переменной RANDOM.

MAXCOUNT=25       # Длина генерируемой последовательности чисел.

random_numbers ()
{
count=0
while [ "$count" -lt "$MAXCOUNT" ]
do
  number=$RANDOM
  echo -n "$number "
  let "count += 1"
done
}

echo; echo

RANDOM=1          # Переустановка начального числа генератора случайных чисел RANDOM.
random_numbers

echo; echo

RANDOM=1          # То же самое начальное число...
random_numbers    # ...в результате получается та же последовательность чисел.
                  #
                  # В каких случаях может оказаться полезной генерация совпадающих серий?

echo; echo

RANDOM=2          # Еще одна попытка, но с другим начальным числом...
random_numbers    # получим другую последовательность.

echo; echo

# RANDOM=$$  в качестве начального числа выбирается PID процесса-сценария.
# Вполне допустимо взять в качестве начального числа результат работы команд 'time' или 'date'.

# Немного воображения...
SEED=$(head -1 /dev/urandom | od -N 1 | awk '{ print $2 }')
#  Псевдослучайное число забирается
#+ из системного генератора псевдослучайных чисел /dev/urandom ,
#+ затем конвертируется в восьмеричное число командой "od",
#+ и наконец "awk" возвращает единственное число для переменной SEED.
RANDOM=$SEED
random_numbers

echo; echo

exit 0
</pre>
            </div>

            <p><a name="URANDOMREF"></a></p>

            <div class="NOTE">
              <table class="NOTE" width="100%" border="0">
                <tbody><tr>
                  <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                  <td align="left" valign="top">
                    <p>Системный генератор <code class="FILENAME">/dev/urandom</code> дает
                    последовательность псевдослучайных чисел с более
                    равномерным распределением, чем <code class="VARNAME">$RANDOM</code>. Команда <code class="USERINPUT"><strong>dd if=/dev/urandom
                    of=targetfile bs=1 count=XX</strong></code> создает
                    файл, содержащий последовательность псевдослучайных
                    чисел. Однако, эти числа требуют дополнительной
                    обработки, например с помощью команды <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ODREF">od</a> (этот прием используется в
                    примере выше) или <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DDREF">dd</a> (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BLOTOUT">Пример 12-42</a>).</p>

                    <p><a name="AWKRANDOMREF"></a></p>

                    <p>Есть и другие способы генерации псевдослучайных
                    последовательностей в сценариях. <strong class="COMMAND">Awk</strong> имеет для этого
                    достаточно удобные средства.</p>

                    <div class="EXAMPLE">
                      <a name="RANDOM2"></a>

                      <p><strong>Пример 9-27. Получение псевдослучайных
                      чисел с помощью <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AWKREF">awk</a></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# random2.sh: Генерация псевдослучайных чисел в диапазоне 0 - 1.
# Используется функция rand() из awk.

AWKSCRIPT=' { srand(); print rand() } '
# Команды/параметры, передаваемые awk
# Обратите внимание, функция srand() переустанавливает начальное число генератора случайных чисел.

echo -n "Случайное число в диапазоне от 0 до 1 = "
echo | awk "$AWKSCRIPT"

exit 0


# Упражнения:
# ---------

# 1) С помощью оператора цикла выведите 10 различных случайных чисел.
#      (Подсказка: вам потребуется вызвать функцию "srand()"
#      в каждом цикле с разными начальными числами.
#      Что произойдет, если этого не сделать?)

# 2) Заставьте сценарий генерировать случайные числа в диапазоне 10 - 100
#      используя целочисленный множитель, как коэффициент масштабирования

# 3) То же самое, что и во втором упражнении,
#      но на этот раз случайные числа должны быть целыми.
</pre>
                    </div>
                  </td>
                </tr>
              </tbody></table>
            </div>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="DBLPARENS"></a>9.7. Двойные круглые скобки</h2>

            <p>Эта конструкция во многом похожа на инструкцию <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LETREF">let</a>, внутри <strong class="COMMAND">((...))</strong> вычисляются
            арифметические выражения и возвращается их результат. В
            простейшем случае, конструкция <code class="USERINPUT"><strong>a=$(( 5 + 3 ))</strong></code>
            присвоит переменной <span class="QUOTE">"a"</span> значение выражения
            <span class="QUOTE">"5 + 3"</span>, или 8. Но, кроме
            того, двойные круглые скобки позволяют работать с
            переменными в стиле языка C.</p>

            <div class="EXAMPLE">
              <a name="CVARS"></a>

              <p><strong>Пример 9-28. Работа с переменными в стиле
              языка C</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Работа с переменными в стиле языка C.


echo

(( a = 23 ))  # Присвоение переменной в стиле C, с обоих строн от "=" стоят пробелы.
echo "a (начальное значение) = $a"

(( a++ ))     # Пост-инкремент 'a', в стиле C.
echo "a (после a++) = $a"

(( a-- ))     # Пост-декремент 'a', в стиле C.
echo "a (после a--) = $a"


(( ++a ))     # Пред-инкремент 'a', в стиле C.
echo "a (после ++a) = $a"

(( --a ))     # Пред-декремент 'a', в стиле C.
echo "a (после --a) = $a"

echo

(( t = a&lt;45?7:11 ))   # Трехместный оператор в стиле языка C.
echo "If a &lt; 45, then t = 7, else t = 11."
echo "t = $t "        # Да!

echo

# См. так же описание ((...))  в циклах "for" и "while".

# Эта конструкция доступна в Bash, начиная с версии 2.04.

exit 0
</pre>
            </div>

            <p>См. так же <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FORLOOPC">Пример 10-12</a>.</p>
          </div>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="LOOPS"></a>Глава 10. Циклы и ветвления</h1>

          <p>Управление ходом исполнения -- один из ключевых моментов
          структурной организации сценариев на языке командной
          оболочки. Циклы и преходы являются теми инструментальными
          средствами, которые обеспечивают управление порядком
          исполнения команд.</p>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="LOOPS1"></a>10.1. Циклы</h2>

            <p><span class="emphasis"><em class="EMPHASIS">Цикл</em></span> -- это блок команд,
            который исполняется многократно до тех пор, пока не будет
            выполнено условие выхода из цикла.</p>

            <div class="VARIABLELIST">
              <p><strong><a name="FORLOOPREF1"></a>циклы for</strong></p>

              <dl>
                <dt><strong class="COMMAND">for (in)</strong></dt>

                <dd>
                  <p>Это одна из основных разновидностей циклов. И она
                  значительно отличается от аналога в языке C.</p>

                  <p><strong class="COMMAND">for</strong> <code class="REPLACEABLE"><em>arg</em></code> in [<code class="REPLACEABLE"><em>list</em></code>]<br>
                   do<br>
                   <code class="REPLACEABLE"><em>&nbsp;команда(ы)</em></code>...<br>
                   done</p>
                  <br>
                  <br>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p>На каждом проходе цикла,
                          переменная-аргумент цикла <code class="REPLACEABLE"><em>arg</em></code>
                          последовательно, одно за другим, принимает
                          значения из списка <code class="REPLACEABLE"><em>list</em></code>.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
<pre class="PROGRAMLISTING">for arg in "$var1" "$var2" "$var3" ... "$varN"
# На первом проходе, $arg = $var1
# На втором проходе, $arg = $var2
# На третьем проходе, $arg = $var3
# ...
# На N-ном проходе, $arg = $varN

# Элементы списка заключены в кавычки для того, чтобы предотвратить возможное разбиение их на отдельные аргументы (слова).
</pre>
                  <br>
                  <br>

                  <p>Элементы списка могут включать в себя шаблонные
                  символы.</p>

                  <p>Есл ключевое слово <strong class="COMMAND">do</strong> находится в одной строке
                  со словом <strong class="COMMAND">for</strong>, то после списка
                  аргументов (перед do) необходимо ставить точку с
                  запятой.</p>

                  <p><strong class="COMMAND">for</strong> <code class="REPLACEABLE"><em>arg</em></code> in [<code class="REPLACEABLE"><em>list</em></code>] ; do<br>
                  </p>
                  <br>
                  <br>

                  <div class="EXAMPLE">
                    <a name="EX22"></a>

                    <p><strong>Пример 10-1. Простой цикл
                    for</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Список планет.

for planet in Меркурий Венера Земля Марс Юпитер Сатурн Уран Нептун Плутон
do
  echo $planet
done

echo

# Если 'список аргументов' заключить в кавычки, то он будет восприниматься как единственный аргумент .
for planet in "Меркурий Венера Земля Марс Юпитер Сатурн Уран Нептун Плутон"
do
  echo $planet
done

exit 0
</pre>
                  </div>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p>Каждый из элементов <code class="USERINPUT"><strong>[списка]</strong></code>
                          может содержать несколько аргументов. Это
                          бывает полезным при обработке групп
                          параметров. В этом случае, для
                          принудительного разбора каждого из аргументов
                          в списке, необходимо использовать инструкцию
                          <strong class="COMMAND">set</strong> (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX34">Пример 11-13</a>).</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>

                  <div class="EXAMPLE">
                    <a name="EX22A"></a>

                    <p><strong>Пример 10-2. Цикл for с двумя
                    параметрами в каждом из элементов
                    списка</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Список планет.

# Имя кажой планеты ассоциировано с расстоянием от планеты до Солнца (млн. миль).

for planet in "Меркурий 36" "Венера 67" "Земля 93"  "Марс 142" "Юпитер 483"
do
  set -- $planet  # Разбиение переменной "planet" на множество аргументов (позиционных параметров).
  # Конструкция "--" предохраняет от неожиданностей, если $planet "пуста" или начинается с символа "-".

  # Если каждый из аргументов потребуется сохранить, поскольку на следующем проходе они будут "забиты" новыми значениями,
  # То можно поместить их в массив,
  #        original_params=("$@")

  echo "$1      в $2,000,000 миль от Солнца"
  #----две табуляции---к параметру $2 добавлены нули
done

# (Спасибо S.C., за разъяснения.)

exit 0
</pre>
                  </div>

                  <p>В качестве списка, в цикле <strong class="COMMAND">for</strong>, можно использовать
                  переменную.</p>

                  <div class="EXAMPLE">
                    <a name="FILEINFO"></a>

                    <p><strong>Пример 10-3. <span class="emphasis"><em class="EMPHASIS">Fileinfo:</em></span> обработка
                    списка файлов, находящегося в
                    переменной</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# fileinfo.sh

FILES="/usr/sbin/privatepw
/usr/sbin/pwck
/usr/sbin/go500gw
/usr/bin/fakefile
/sbin/mkreiserfs
/sbin/ypbind"     # Список интересующих нас файлов.
                  # В список добавлен фиктивный файл /usr/bin/fakefile.

echo

for file in $FILES
do

  if [ ! -e "$file" ]       # Проверка наличия файла.
  then
    echo "Файл $file не найден."; echo
    continue                # Переход к следующей итерации.
  fi

  ls -l $file | awk '{ print $8 "         размер: " $5 }'  # Печать 2 полей.
  whatis `basename $file`   # Информация о файле.
  echo
done  

exit 0
</pre>
                  </div>

                  <p>В <code class="USERINPUT"><strong>[списке]</strong></code>
                  цикла <strong class="COMMAND">for</strong> могут быть использованы
                  имена файлов, которые в свою очередь могут содержать
                  символы-шаблоны.</p>

                  <div class="EXAMPLE">
                    <a name="LISTGLOB"></a>

                    <p><strong>Пример 10-4. Обработка списка файлов в
                    цикле for</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# list-glob.sh: Создание список файлов в цикле for с использованием
# операции подстановки имен файлов ("globbing").

echo

for file in *
do
  ls -l "$file"  # Список всех файлов в $PWD (текущем каталоге).
  # Напоминаю, что символу "*" соответствует любое имя файла,
  # однако, в операциях подстановки имен файлов ("globbing"),
  # имеются исключения -- имена файлов, начинающиеся с точки.

  # Если в каталоге нет ни одного файла, соответствующего шаблону,
  # то за имя файла принимается сам шаблон.
  # Чтобы избежать этого, используйте ключ nullglob
  # (shopt -s nullglob).
  # Спасибо S.C.
done

echo; echo

for file in [jx]*
do
  rm -f $file    # Удаление файлов, начинающихся с "j" или "x" в $PWD.
  echo "Удален файл \"$file\"".
done

echo

exit 0
</pre>
                  </div>

                  <p>Если <code class="USERINPUT"><strong>[список]</strong></code> в
                  цикле <strong class="COMMAND">for</strong> не задан, то в качестве
                  оного используется переменная <span class="TOKEN">$@</span> -- список аргументов
                  командной строки. Оень остроумно эта особенность
                  проиллюстрирована в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PRIMES">Пример A-18</a>.</p>

                  <div class="EXAMPLE">
                    <a name="EX23"></a>

                    <p><strong>Пример 10-5. Цикл for без списка
                    аргументов</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# Попробуйте вызвать этот сценарий с аргументами и без них и посмотреть на результаты.

for a
do
 echo -n "$a "
done

#  Список аргументов не задан, поэтому цикл работает с переменной '$@'
#+ (список аргументов командной строки, включая пробельные символы).

echo

exit 0
</pre>
                  </div>

                  <p>При создании списка аргументов, в цикле for
                  допускается пользоваться <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COMMANDSUBREF">подстановкой команд</a>. См.
                  <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX53">Пример 12-39</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SYMLINKS">Пример 10-10</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BASE">Пример 12-33</a>.</p>

                  <div class="EXAMPLE">
                    <a name="FORLOOPCMD"></a>

                    <p><strong>Пример 10-6. Создание списка аргументов
                    в цикле for с помощью операции подстановки
                    команд</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# уЩЫЬ for гЯ [гаЩгЫЯЭ], гЯкФСЮЮйЭ г аЯЭЯниР аЯФгдСЮЯзЫЩ ЫЯЭСЮФ.

NUMBERS="9 7 3 8 37.53"

for number in `echo $NUMBERS`  # for number in 9 7 3 8 37.53
do
  echo -n "$number "
done

echo 
exit 0
</pre>
                  </div>

                  <p>Более сложный пример использования подстановки
                  команд при создании списка аргументов цикла.</p>

                  <div class="EXAMPLE">
                    <a name="BINGREP"></a>

                    <p><strong>Пример 10-7. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GREPREF">grep</a> для бинарных
                    файлов</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# bin-grep.sh: Поиск строк в двоичных файлах.

# замена "grep" для бинарных файлов.
# Аналогично команде "grep -a"

E_BADARGS=65
E_NOFILE=66

if [ $# -ne 2 ]
then
  echo "Порядок использования: `basename $0` string filename"
  exit $E_BADARGS
fi

if [ ! -f "$2" ]
then
  echo "Файл \"$2\" не найден."
  exit $E_NOFILE
fi


for word in $( strings "$2" | grep "$1" )
# Инструкция "strings" возвращает список строк в двоичных файлах.
# Который затем передается по конвейеру команде "grep", для выполнения поиска.
do
  echo $word
done

# Как указывает S.C., вышепрведенное объявление цикла for может быть упрощено
#    strings "$2" | grep "$1" | tr -s "$IFS" '[\n*]'


# Попробуйте что нибудь подобное:  "./bin-grep.sh mem /bin/ls"

exit 0
</pre>
                  </div>

                  <p>Еще один пример.</p>

                  <div class="EXAMPLE">
                    <a name="USERLIST"></a>

                    <p><strong>Пример 10-8. Список всех пользователей
                    системы</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# userlist.sh

PASSWORD_FILE=/etc/passwd
n=1           # Число пользователей

for name in $(awk 'BEGIN{FS=":"}{print $1}' &lt; "$PASSWORD_FILE" )
# Разделитель полей = :  ^^^^^^
# Вывод первого поля              ^^^^^^^^
# Данные берутся из файла паролей            ^^^^^^^^^^^^^^^^^
do
  echo "Пользователь #$n = $name"
  let "n += 1"
done


# Пользователь #1 = root
# Пользователь #2 = bin
# Пользователь #3 = daemon
# ...
# Пользователь #30 = bozo

exit 0
</pre>
                  </div>

                  <p>И заключительный пример использования подстановки
                  команд при создании [списка].</p>

                  <div class="EXAMPLE">
                    <a name="FINDSTRING"></a>

                    <p><strong>Пример 10-9. Проверка авторства всех
                    бинарных файлов в текущем каталоге</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# findstring.sh:
# Поиск заданной строки в двоичном файле.

directory=/usr/local/bin/
fstring="Free Software Foundation"  # Поиск файлов от FSF.

for file in $( find $directory -type f -name '*' | sort )
do
  strings -f $file | grep "$fstring" | sed -e "s%$directory%%"
  #  Команде "sed" передается выражение (ключ -e),
  #+ для того, чтобы изменить обычный разделитель "/" строки поиска и строки замены
  #+ поскольку "/" - один из отфильтровываемых символов.
  #  Использование такого символа порождает сообщение об ошибке (попробуйте).
done

exit 0

#  Упражнение:
#  ---------------
#  Измените сценарий таким образом, чтобы он брал
#+ $directory и $fstring из командной строки.
</pre>
                  </div>

                  <p>Результат работы цикла <strong class="COMMAND">for</strong> может передаваться
                  другим командам по конвейеру.</p>

                  <div class="EXAMPLE">
                    <a name="SYMLINKS"></a>

                    <p><strong>Пример 10-10. Список символических
                    ссылок в каталоге</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# symlinks.sh: Список символических ссылок в каталоге.


directory=${1-`pwd`}
#  По-умолчанию в текущем каталоге,
#  Блок кода, который выполняет аналогичные действия.
# ----------------------------------------------------------
# ARGS=1                 # Ожидается один аргумент командной строки.
#
# if [ $# -ne "$ARGS" ]  # Если каталог поиска не задан...
# then
#   directory=`pwd`      # текущий каталог
# else
#   directory=$1
# fi
# ----------------------------------------------------------

echo "символические ссылки в каталоге \"$directory\""

for file in "$( find $directory -type l )"   # -type l = символические ссылки
do
  echo "$file"
done | sort             # В противном случае получится неотсортированный список.

#  Как отмечает Dominik 'Aeneas' Schnitzer,
#+ в случае отсутствия кавычек для $( find $directory -type l )
#+ сценарий "подавится" именами файлов, содержащими пробелы.

exit 0
</pre>
                  </div>

                  <p>Вывод цикла может быть <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IOREDIRREF">перенаправлен</a> со <code class="FILENAME">stdout</code> в файл, ниже приводится
                  немного модифицированный вариант предыдущего примера,
                  демонстрирующий эту возможность.</p>

                  <div class="EXAMPLE">
                    <a name="SYMLINKS2"></a>

                    <p><strong>Пример 10-11. Список символических
                    ссылок в каталоге, сохраняемый в файле</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# symlinks.sh: Список символических ссылок в каталоге.

OUTFILE=symlinks.list                         # файл со списком

directory=${1-`pwd`}
#  По-умолчанию -- текущий каталог,

echo "символические ссылки в каталоге \"$directory\"" &gt; "$OUTFILE"
echo "---------------------------" &gt;&gt; "$OUTFILE"

for file in "$( find $directory -type l )"    # -type l = символические ссылки
do
  echo "$file"
done | sort &gt;&gt; "$OUTFILE"                     # перенаправление вывода
#           ^^^^^^^^^^^^^                       в файл.

exit 0
</pre>
                  </div>

                  <p>Оператор цикла <strong class="COMMAND">for</strong> имеет и альтернативный
                  синтаксис записи -- очень похожий на синтаксис
                  оператора for в языке C. Для этого используются
                  двойные круглые скобки.</p>

                  <div class="EXAMPLE">
                    <a name="FORLOOPC"></a>

                    <p><strong>Пример 10-12. C-подобный синтаксис
                    оператора цикла for</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Два вапианта оформления цикла.

echo

# Стандартный синтаксис.
for a in 1 2 3 4 5 6 7 8 9 10
do
  echo -n "$a "
done

echo; echo

# +==========================================+

# А теперь C-подобный синтаксис.

LIMIT=10

for ((a=1; a &lt;= LIMIT ; a++))  # Двойные круглые скобки и "LIMIT" без "$".
do
  echo -n "$a "
done                           # Конструкция заимствована из 'ksh93'.

echo; echo

# +=========================================================================+

# Попробуем и C-шный оператор "запятая".

for ((a=1, b=1; a &lt;= LIMIT ; a++, b++))  # Запятая разделяет две операции, которые выполняются совместно.
do
  echo -n "$a-$b "
done

echo; echo

exit 0
</pre>
                  </div>

                  <p>См. так же <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#QFUNCTION">Пример 25-10</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TWODIM">Пример 25-11</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COLLATZ">Пример A-7</a>.</p>

                  <p>---</p>

                  <p>А сейчас пример сценария, который может найти
                  "реальное" применение.</p>

                  <div class="EXAMPLE">
                    <a name="EX24"></a>

                    <p><strong>Пример 10-13. Работа с командой efax в
                    пакетном режиме</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

EXPECTED_ARGS=2
E_BADARGS=65

if [ $# -ne $EXPECTED_ARGS ]
# Проверка наличия аргументов командной строки.
then
   echo "Порядок использования: `basename $0` phone# text-file"
   exit $E_BADARGS
fi


if [ ! -f "$2" ]
then
  echo "Файл $2 не является текстовым файлом"
  exit $E_BADARGS
fi


fax make $2              # Создать fax-файлы из текстовых файлов.

for file in $(ls $2.0*)  # Все файлы, получившиеся в результате преобразования.
                         # Используется шаблонный символ в списке.
do
  fil="$fil $file"
done

efax -d /dev/ttyS3 -o1 -t "T$1" $fil   # отправить.


# Как указывает S.C., в цикл for может быть вставлена сама команда отправки в виде:
#    efax -d /dev/ttyS3 -o1 -t "T$1" $2.0*
# но это не так поучительно [;-)].

exit 0
</pre>
                  </div>
                </dd>

                <dt><a name="WHILELOOPREF"></a><strong class="COMMAND">while</strong></dt>

                <dd>
                  <p>Оператор while проверяет условие перед началом
                  каждой итерации и если условие истинно (если <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXITSTATUSREF">код возврата</a> равен <span class="RETURNVALUE">0</span>), то управление
                  передается в тело цикла. В отличие от циклов <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FORLOOPREF1">for</a>, циклы <span class="emphasis"><em class="EMPHASIS">while</em></span> используются в
                  тех случаях, когда количество итераций заранее не
                  известно.</p>

                  <p><strong class="COMMAND">while</strong> [<code class="REPLACEABLE"><em>condition</em></code>]<br>
                   do<br>
                   <code class="REPLACEABLE"><em>&nbsp;command</em></code>...<br>
                   done</p>
                  <br>
                  <br>

                  <p>Как и в случае с циклами <span class="TOKEN">for/in</span>, при размещении
                  ключевого слова <strong class="COMMAND">do</strong> в одной строке с
                  объявлением цикла, необходимо вставлять символ
                  ";" перед <strong class="COMMAND">do</strong>.</p>

                  <p><strong class="COMMAND">while</strong> [<code class="REPLACEABLE"><em>condition</em></code>] ;
                  do</p>
                  <br>
                  <br>

                  <p>Обратите внимание: в отдельных случаях, таких как
                  использование конструкции <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GETOPTSX">getopts</a> совместно с оператором
                  <strong class="COMMAND">while</strong>, синтаксис несколько
                  отличается от приводимого здесь.</p>

                  <div class="EXAMPLE">
                    <a name="EX25"></a>

                    <p><strong>Пример 10-14. Простой цикл
                    while</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

var0=0
LIMIT=10

while [ "$var0" -lt "$LIMIT" ]
do
  echo -n "$var0 "        # -n подавляет перевод строки.
  var0=`expr $var0 + 1`   # допускается var0=$(($var0+1)).
done

echo

exit 0
</pre>
                  </div>

                  <div class="EXAMPLE">
                    <a name="EX26"></a>

                    <p><strong>Пример 10-15. Другой пример цикла
                    while</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

echo

while [ "$var1" != "end" ]     # возможна замена на while test "$var1" != "end"
do
  echo "Введите значение переменной #1 (end - выход) "
  read var1                    # Конструкция 'read $var1' недопустима (почему?).
  echo "переменная #1 = $var1" # кавычки обязательны, потому что имеется символ "#".
  # Если введено слово 'end', то оно тоже выводится на экран.
  # потому, что проверка переменной выполняется в начале итерации (перед вводом).
  echo
done  

exit 0
</pre>
                  </div>

                  <p>Оператор <strong class="COMMAND">while</strong> может иметь несколько
                  условий. Но только последнее из них определяет
                  возможность продолжения цикла. В этом случае
                  синтаксис оператора цикла должен быть несколько
                  иным.</p>

                  <div class="EXAMPLE">
                    <a name="EX26A"></a>

                    <p><strong>Пример 10-16. Цикл while с несколькими
                    условиями</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

var1=unset
previous=$var1

while echo "предыдущее значение = $previous"
      echo
      previous=$var1     # запомнить предыдущее значение
      [ "$var1" != end ]
      # В операторе "while" присутствуют 4 условия, но только последнее управляет циклом.
      # *последнее* условие - единственное, которое вычисляется.
do
echo "Введите значение переменной #1 (end - выход) "
  read var1
  echo "текущее значение = $var1"
done

# попробуйте самостоятельно разобраться в сценарии works.

exit 0
</pre>
                  </div>

                  <p>Как и в случае с <strong class="COMMAND">for</strong>, цикл <strong class="COMMAND">while</strong> может быть записан в
                  C-подобной нотации, с использованием двойных круглых
                  скобок (см. так же <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CVARS">Пример 9-28</a>).</p>

                  <div class="EXAMPLE">
                    <a name="WHLOOPC"></a>

                    <p><strong>Пример 10-17. C-подобный синтаксис
                    оформления цикла while</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# wh-loopc.sh: Цикл перебора от 1 до 10.

LIMIT=10
a=1

while [ "$a" -le $LIMIT ]
do
  echo -n "$a "
  let "a+=1"
done           # Пока ничего особенного.

echo; echo

# +=================================================================+

# А теперь оформим в стиле языка C.

((a = 1))      # a=1
# Двойные скобки допускают наличие лишних пробелов в выражениях.

while (( a &lt;= LIMIT ))   # В двойных скобках символ "$" перед переменными опускается.
do
  echo -n "$a "
  ((a += 1))   # let "a+=1"
  # Двойные скобки позволяют наращивание переменной в стиле языка C.
done

echo

# Теперь, программисты, пишущие на C, могут чувствовать себя в Bash как дома.

exit 0
</pre>
                  </div>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p>Стандартное устройство ввода <code class="FILENAME">stdin</code>, для цикла
                          <strong class="COMMAND">while</strong>, можно <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REDIRREF">перенаправить на файл</a> с
                          помощью команды перенаправления <span class="TOKEN">&lt;</span> в конце цикла.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><a name="UNTILLOOPREF"></a><strong class="COMMAND">until</strong></dt>

                <dd>
                  <p>Оператор цикла <strong class="COMMAND">until</strong> проверяет условие в
                  начале каждой итерации, но в отличие от <strong class="COMMAND">while</strong> итерация возможна
                  только в том случае, если условие ложно.</p>

                  <p><strong class="COMMAND">until</strong> [<code class="REPLACEABLE"><em>condition-is-true</em></code>]<br>
                   do<br>
                   <code class="REPLACEABLE"><em>&nbsp;command</em></code>...<br>
                   done</p>
                  <br>
                  <br>

                  <p>Обратите внимание: оператор <strong class="COMMAND">until</strong> проверяет условие
                  завершения цикла ПЕРЕД очередной итерацией, а не
                  после, как это принято в некоторых языках
                  программирования.</p>

                  <p>Как и в случае с циклами <span class="TOKEN">for/in</span>, при размещении
                  ключевого слова <strong class="COMMAND">do</strong> в одной строке с
                  объявлением цикла, необходимо вставлять символ
                  ";" перед <strong class="COMMAND">do</strong>.</p>

                  <p><strong class="COMMAND">until</strong> [<code class="REPLACEABLE"><em>condition-is-true</em></code>]
                  ; do</p>
                  <br>
                  <br>

                  <div class="EXAMPLE">
                    <a name="EX27"></a>

                    <p><strong>Пример 10-18. Цикл until</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

until [ "$var1" = end ] # Проверка условия производится в начале итерации.
do
  echo "Введите значение переменной #1 "
  echo "(end - выход)"
  read var1
  echo "значение переменной #1 = $var1"
done  

exit 0
</pre>
                  </div>
                </dd>
              </dl>
            </div>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="NESTEDLOOPS"></a>10.2. Вложенные циклы</h2>

            <p>Цикл называется вложенным, если он размещается внутри
            другого цикла. На первом проходе, внешний цикл вызывает
            внутренний, который исполняется до своего завершения, после
            чего управление передается в тело внешнего цикла. На втором
            проходе внешний цикл опять вызывает внутренний. И так до
            тех пор, пока не завершится внешний цикл. Само собой, как
            внешний, так и внутренний циклы могут быть прерваны
            командой <strong class="COMMAND">break</strong>.</p>

            <div class="EXAMPLE">
              <a name="NESTEDLOOP"></a>

              <p><strong>Пример 10-19. Вложенный цикл</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Вложенные циклы "for".

outer=1             # Счетчик внешнего цикла.

# Начало внешнего цикла.
for a in 1 2 3 4 5
do
  echo "Итерация #$outer внешнего цикла."
  echo "---------------------"
  inner=1           # Сброс счетчика вложенного цикла.

  # Начало вложенного цикла.
  for b in 1 2 3 4 5
  do
    echo "Итерация #$inner вложенного цикла."
    let "inner+=1"  # Увеличить счетчик итераций вложенного цикла.
  done
  # Конец вложенного цикла.

  let "outer+=1"    # Увеличить счетчик итераций внешнего цикла.
  echo              # Пустая строка для отделения итераций внешнего цикла.
done
# Конец внешнего цикла.

exit 0
</pre>
            </div>

            <p>Демонстрацию вложенных циклов <span class="QUOTE">"while"</span> вы найдете в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BUBBLE">Пример 25-6</a>, а вложение цикла <span class="QUOTE">"while"</span> в <span class="QUOTE">"until"</span> -- в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX68">Пример 25-8</a>.</p>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="LOOPCONTROL"></a>10.3. Управление ходом выполнения
            цикла</h2>

            <div class="VARIABLELIST">
              <dl>
                <dt><strong class="COMMAND">break</strong>, <strong class="COMMAND">continue</strong></dt>

                <dd>
                  <p>Для управления ходом выполнения цикла служат
                  команды <strong class="COMMAND">break</strong> и <strong class="COMMAND">continue</strong> <a name="AEN5175" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN5175"><span class="footnote">[23]</span></a> и точно
                  соответствуют своим аналогам в других языках
                  программирования. Команда <strong class="COMMAND">break</strong> прерывает исполнение
                  цикла, в то время как <strong class="COMMAND">continue</strong> передает
                  управление в начало цикло, минуя все последующие
                  команды в теле цикла.</p>

                  <div class="EXAMPLE">
                    <a name="EX28"></a>

                    <p><strong>Пример 10-20. Команды break и continue в
                    цикле</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

LIMIT=19  # Верхний предел

echo
echo "Печать чисел от 1 до 20 (исключая 3 и 11)."

a=0

while [ $a -le "$LIMIT" ]
do
 a=$(($a+1))

 if [ "$a" -eq 3 ] || [ "$a" -eq 11 ]  # Исключить 3 и 11
 then
   continue  # Переход в начало цикла.
 fi

 echo -n "$a "
done

# Упражнение:
# Почему число 20 тоже выводится?

echo; echo

echo Печать чисел от 1 до 20, но взгляните, что происходит после вывода числа 2

##################################################################

# Тот же цикл, только 'continue' заменено на 'break'.

a=0

while [ "$a" -le "$LIMIT" ]
do
 a=$(($a+1))

 if [ "$a" -gt 2 ]
 then
   break  # Завершение работы цикла.
 fi

 echo -n "$a "
done

echo; echo; echo

exit 0
</pre>
                  </div>

                  <p>Команде <strong class="COMMAND">break</strong> может быть передан
                  необязательный параметр. Команда <strong class="COMMAND">break</strong> без параметра
                  прерывает тот цикл, в который она вставлена, а
                  <strong class="COMMAND">break N</strong> прерывает цикл,
                  стоящий на N уровней выше (причем 1-й уровень -- это
                  уровень текущего цикла, прим. перев.).</p>

                  <div class="EXAMPLE">
                    <a name="BREAKLEVELS"></a>

                    <p><strong>Пример 10-21. Прерывание многоуровневых
                    циклов</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# break-levels.sh: Прерывание циклов.

# "break N" прерывает исполнение цикла, стоящего на N уровней выше текущего.

for outerloop in 1 2 3 4 5
do
  echo -n "Группа $outerloop:   "

  for innerloop in 1 2 3 4 5
  do
    echo -n "$innerloop "

    if [ "$innerloop" -eq 3 ]
    then
      break  # Попробуйте "break 2",
             # тогда будут прерываться как вложенный, так и внешний циклы
    fi
  done

  echo
done  

echo

exit 0
</pre>
                  </div>

                  <p>Команда <strong class="COMMAND">continue</strong>, как и команда
                  <strong class="COMMAND">break</strong>, может иметь
                  необязательный параметр. В простейшем случае, команда
                  <strong class="COMMAND">continue</strong> передает
                  управление в начало текущего цикла, а команда <strong class="COMMAND">continue N</strong> прерывает
                  исполнение текущего цикла и передает управление в
                  начало внешнего цикла, отстоящего от текущего на N
                  уровней (причем 1-й уровень -- это уровень текущего
                  цикла, прим. перев.).</p>

                  <div class="EXAMPLE">
                    <a name="CONTINUELEVELS"></a>

                    <p><strong>Пример 10-22. Передача управление в
                    начало внешнего цикла</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Команда "continue N" передает управление в начало внешнего цикла, отстоящего от текущего на N уровней.

for outer in I II III IV V           # внешний цикл
do
  echo; echo -n "Группа $outer: "

  for inner in 1 2 3 4 5 6 7 8 9 10  # вложенный цикл
  do

    if [ "$inner" -eq 7 ]
    then
      continue 2  # Передача управления в начало цикла 2-го уровня.
                  # попробуйте убрать параметр 2 команды "continue"
    fi

    echo -n "$inner "  # 8 9 10 никогда не будут напечатаны.
  done

done

echo; echo

# Упражнение:
# Подумайте, где реально можно использовать "continue N" в сценариях.

exit 0
</pre>
                  </div>

                  <div class="EXAMPLE">
                    <a name="CONTINUENEX"></a>

                    <p><strong>Пример 10-23. Живой пример использования
                    <span class="QUOTE">"continue
                    N"</span></strong></p>
<pre class="PROGRAMLISTING"># Albert Reiner привел пример использования "continue N":
# ---------------------------------------------------------

#  Допустим, у меня есть большое количество задач, обрабатывающие некоторые данные,
#+ которые хранятся в некоторых файлах, с именами, задаваемыми по шаблону,
#+ в заданном каталоге.
#+ Есть несколько машин, которым открыт доступ к этому каталогу
#+ и я хочу распределить обработку информации между машинами.
#+ тогда я обычно для каждой машины пишу нечто подобное:

while true
do
  for n in .iso.*
  do
    [ "$n" = ".iso.opts" ] &amp;&amp; continue
    beta=${n#.iso.}
    [ -r .Iso.$beta ] &amp;&amp; continue
    [ -r .lock.$beta ] &amp;&amp; sleep 10 &amp;&amp; continue
    lockfile -r0 .lock.$beta || continue
    echo -n "$beta: " `date`
    run-isotherm $beta
    date
    ls -alF .Iso.$beta
    [ -r .Iso.$beta ] &amp;&amp; rm -f .lock.$beta
    continue 2
  done
  break
done

#  Конкретная реализация цикла, особенно sleep N, зависит от конкретных применений,
#+ но в общем случае он строится по такой схеме:

while true
do
  for job in {шаблон}
  do
    {файл уже обработан или обрабатывается} &amp;&amp; continue
    {пометить файл как обрабатываемый, обработать, пометить как обработанный}
    continue 2
  done
  break        # Или что нибудь подобное `sleep 600', чтобы избежать завершения.
done

#  Этот сценарий завершит работу после того как все данные будут обработаны
#+ (включая данные, которые поступили во время обработки). Использование
#+ соответствующих lock-файлоа позволяет вести обработку на нескольких машинах
#+ одновременно, не производя дублирующих вычислений [которые, в моем случае,
#+ выполняются в течении нескольких часов, так что для меня это очень важно].
#+ Кроме того, поскольку поиск необработанных файлов всегда начинается с
#+ самого начала, можно задавать приоритеты в именах файлов. Конечно, можно
#+ обойтись и без `continue 2', но тогда придется ввести дополнительную
#+ проверку -- действительно ли был обработан тот или иной файл
#+ (чтобы перейти к поиску следующего необработанного файла).
</pre>
                  </div>

                  <div class="CAUTION">
                    <table class="CAUTION" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                        <td align="left" valign="top">
                          <p>Конструкция <strong class="COMMAND">continue N</strong> довольно
                          сложна в понимании и применении, поэтому,
                          вероятно лучше будет постараться избегать ее
                          использования.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>
              </dl>
            </div>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="TESTBRANCH"></a>10.4. Операторы выбора</h2>

            <p>Инструкции <strong class="COMMAND">case</strong> и <strong class="COMMAND">select</strong> технически не являются
            циклами, поскольку не предусматривают многократное
            исполнение блока кода. Однако, они, как и циклы, управляют
            ходом исполнения программы, в зависимости от начальных или
            конечных условий.</p>

            <div class="VARIABLELIST">
              <p><strong><a name="CASEESAC1"></a></strong></p>

              <dl>
                <dt><strong class="COMMAND">case (in) / esac</strong></dt>

                <dd>
                  <p>Конструкция <strong class="COMMAND">case</strong> эквивалентна
                  конструкции <strong class="COMMAND">switch</strong> в языке C/C++. Она
                  позволяет выполнять тот или иной участок кода, в
                  зависимости от результатов проверки условий. Она
                  является, своего рода, краткой формой записи большого
                  количества операторов <span class="TOKEN">if/then/else</span> и может быть
                  неплохим инструментом при создании разного рода
                  меню.</p>

                  <p><strong class="COMMAND">case</strong> "$<code class="REPLACEABLE"><em>variable</em></code>"
                  in<br>
                  <br>
                   &nbsp;"$<code class="REPLACEABLE"><em>condition1</em></code>"
                  )<br>
                   &nbsp;<code class="REPLACEABLE"><em>command</em></code>...<br>
                   &nbsp;;;<br>
                  <br>
                   &nbsp;"$<code class="REPLACEABLE"><em>condition2</em></code>"
                  )<br>
                   &nbsp;<code class="REPLACEABLE"><em>command</em></code>...<br>
                   &nbsp;;;<br>
                  <br>
                   esac</p>
                  <br>
                  <br>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <ul>
                            <li>
                              <p>Заключать переменные в кавычки
                              необязательно, поскольку здесь не
                              производится разбиения на отдельные
                              слова.</p>
                            </li>

                            <li>
                              <p>Каждая строка с условием должна
                              завершаться правой (закрывающей) круглой
                              скобкой <span class="TOKEN">)</span>.</p>
                            </li>

                            <li>
                              <p>Каждый блок команд, отрабатывающих по
                              заданному условию, должен завершаться
                              <span class="emphasis"><em class="EMPHASIS">двумя</em></span>
                              символами точка-с-запятой <span class="TOKEN">;;</span>.</p>
                            </li>

                            <li>
                              <p>Блок <strong class="COMMAND">case</strong> должен
                              завершаться ключевым словом <strong class="COMMAND">esac</strong> (<em class="WORDASWORD">case</em> записанное
                              в обратном порядке).</p>
                            </li>
                          </ul>
                          <br>
                          <br>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>

                  <div class="EXAMPLE">
                    <a name="EX29"></a>

                    <p><strong>Пример 10-24. Использование
                    case</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

echo; echo "Нажмите клавишу и затем клавишу Return."
read Keypress

case "$Keypress" in
  [a-z]   ) echo "буква в нижнем регистре";;
  [A-Z]   ) echo "Буква в верхнем регистре";;
  [0-9]   ) echo "Цифра";;
  *       ) echo "Знак пунктуации, пробел или что-то другое";;
esac  # Допускается указыватль диапазоны символов в [квадратных скобках].

# Упражнение:
# --------
# Сейчас сценарий считывает нажатую клавишу и завершается.
# Измените его так, чтобы сценарий продолжал отвечать на нажатия клавиш,
# но завершался бы только после ввода символа "X".
# Подсказка: заключите все в цикл "while".

exit 0
</pre>
                  </div>

                  <div class="EXAMPLE">
                    <a name="EX30"></a>

                    <p><strong>Пример 10-25. Создание меню с помощью
                    case</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# Грубый пример базы данных

clear # Очистка экрана

echo "          Список"
echo "          ------"
echo "Выберите интересующую Вас персону:"
echo
echo "[E]vans, Roland"
echo "[J]ones, Mildred"
echo "[S]mith, Julie"
echo "[Z]ane, Morris"
echo

read person

case "$person" in
# Обратите внимание: переменная взята в кавычки.

  "E" | "e" )
  # Пользователь может ввести как заглавную, так и строчную букву.
  echo
  echo "Roland Evans"
  echo "4321 Floppy Dr."
  echo "Hardscrabble, CO 80753"
  echo "(303) 734-9874"
  echo "(303) 734-9892 fax"
  echo "revans@zzy.net"
  echo "Старый друг и партнер по бизнесу"
  ;;
# Обратите внимание: блок кода, анализирующий конкретный выбор, завершается
# двумя символами "точка-с-запятой".

  "J" | "j" )
  echo
  echo "Mildred Jones"
  echo "249 E. 7th St., Apt. 19"
  echo "New York, NY 10009"
  echo "(212) 533-2814"
  echo "(212) 533-9972 fax"
  echo "milliej@loisaida.com"
  echo "Подружка"
  echo "День рождения: 11 февраля"
  ;;

# Информация о Smith и Zane будет добавлена позднее.

          * )
   # Выбор по-умолчанию.
   # "Пустой" ввод тоже обрабатывается здесь.
   echo
   echo "Нет данных."
  ;;

esac

echo

#  Упражнение:
#  --------
#  Измените этот сценарий таким образом, чтобы он не завершал работу
#+ после вывода информации о персоне, а переходил на ожидание нового
#+ ввода от пользователя.

exit 0
</pre>
                  </div>

                  <p>Очень хороший пример использования <strong class="COMMAND">case</strong> для анализа
                  аргументов, переданных из командной строки.</p>
<pre class="PROGRAMLISTING">#! /bin/bash

case "$1" in
"") echo "Порядок использования: ${0##*/} &lt;filename&gt;"; exit 65;;  # Параметры командной строки отсутствуют,
                                                  # или первый параметр -- "пустой".
# Обратите внимание на ${0##*/} это подстановка параметра ${var##pattern}. В результате получается $0.

-*) FILENAME=./$1;;   # Если имя файла (аргумент $1) начинается с "-",
                      # то заменить его на ./$1
                      # тогда параметр не будет восприниматься как ключ команды.

* ) FILENAME=$1;;     # В противном случае -- $1.
esac
</pre>
                  <br>
                  <br>

                  <div class="EXAMPLE">
                    <a name="CASECMD"></a>

                    <p><strong>Пример 10-26. Оператор case допускает
                    использовать подстановку команд вместо
                    анализируемой переменной</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Подстановка команд в "case".

case $( arch ) in # команда "arch" возвращает строку, описывающую аппаратную апхитектуру.
i386 ) echo "Машина на базе процессора 80386";;
i486 ) echo "Машина на базе процессора 80486";;
i586 ) echo "Машина на базе процессора Pentium";;
i686 ) echo "Машина на базе процессора Pentium2 или выше";;
*    ) echo "Машина на другом типе процессора";;
esac

exit 0
</pre>
                  </div>

                  <p>Оператор <strong class="COMMAND">case</strong> допускает
                  использование шаблонных конструкций.</p>

                  <div class="EXAMPLE">
                    <a name="MATCHSTRING"></a>

                    <p><strong>Пример 10-27. Простой пример сравнения
                    строк</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# match-string.sh: простое сравнение строк

match_string ()
{
  MATCH=0
  NOMATCH=90
  PARAMS=2     # Функция требует два входных аргумента.
  BAD_PARAMS=91

  [ $# -eq $PARAMS ] || return $BAD_PARAMS

  case "$1" in
  "$2") return $MATCH;;
  *   ) return $NOMATCH;;
  esac

}


a=one
b=two
c=three
d=two


match_string $a     # неверное число аргументов
echo $?             # 91

match_string $a $b  # не равны
echo $?             # 90

match_string $b $d  # равны
echo $?             # 0


exit 0
</pre>
                  </div>

                  <div class="EXAMPLE">
                    <a name="ISALPHA"></a>

                    <p><strong>Пример 10-28. Проверка
                    ввода</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# isalpha.sh: Использование "case" для анализа строк.

SUCCESS=0
FAILURE=-1

isalpha ()  # Проверка - является ли первый символ строки символом алфавита.
{
if [ -z "$1" ]                # Вызов функции без входного аргумента?
then
  return $FAILURE
fi

case "$1" in
[a-zA-Z]*) return $SUCCESS;;  # Первый символ - буква?
*        ) return $FAILURE;;
esac
}             # Сравните с функцией "isalpha ()" в языке C.


isalpha2 ()   # Проверка - состоит ли вся строка только из символов алфавита.
{
  [ $# -eq 1 ] || return $FAILURE

  case $1 in
  *[!a-zA-Z]*|"") return $FAILURE;;
               *) return $SUCCESS;;
  esac
}

isdigit ()    # Проверка - состоит ли вся строка только из цифр.
{             # Другими словами - является ли строка целым числом.
  [ $# -eq 1 ] || return $FAILURE

  case $1 in
  *[!0-9]*|"") return $FAILURE;;
            *) return $SUCCESS;;
  esac
}



check_var ()  # Интерфейс к isalpha
{
if isalpha "$@"
then
  echo "\"$*\" начинается с алфавитного символа."
  if isalpha2 "$@"
  then        # Дальнейшая проверка не имеет смысла, если первй символ не буква.
    echo "\"$*\" содержит только алфавитные символы."
  else
    echo "\"$*\" содержит по меньшей мере один не алфавитный символ."
  fi
else
  echo "\"$*\" начинсется с не алфавитного символа ."
              #  Если функция вызвана без входного параметра,
              #+ то считается, что строка содержит "не алфавитной" символ.
fi

echo

}

digit_check ()  # Интерфейс к isdigit ().
{
if isdigit "$@"
then
  echo "\"$*\" содержит только цифры [0 - 9]."
else
  echo "\"$*\" содержит по меньшей мере один не цифровой символ."
fi

echo

}

a=23skidoo
b=H3llo
c=-What?
d=What?
e=`echo $b`   # Подстановка команды.
f=AbcDef
g=27234
h=27a34
i=27.34

check_var $a
check_var $b
check_var $c
check_var $d
check_var $e
check_var $f
check_var     # Вызов без параметра, что произойдет?
#
digit_check $g
digit_check $h
digit_check $i


exit 0        # Сценарий дополнен S.C.

# Упражнение:
# --------
#  Напишите функцию 'isfloat ()', которая проверяла бы вещественные числа.
#  Подсказка: Эта функция подобна функции 'isdigit ()',
#+ надо лишь добавить анализ наличия десятичной точки.
</pre>
                  </div>
                </dd>

                <dt><a name="SELECTREF"></a><strong class="COMMAND">select</strong></dt>

                <dd>
                  <p>Оператор <strong class="COMMAND">select</strong> был заимствован из
                  Korn Shell, и является еще одним инструментом,
                  используемым при создании меню.</p>

                  <p><strong class="COMMAND">select</strong> <code class="REPLACEABLE"><em>variable</em></code> [in <code class="REPLACEABLE"><em>list</em></code>]<br>
                   do<br>
                   &nbsp;<code class="REPLACEABLE"><em>command</em></code>...<br>
                   &nbsp;break<br>
                   done</p>
                  <br>
                  <br>

                  <p>Этот оператор предлагает пользователю выбрать один
                  из представленных вариантов. Примечательно, что
                  <strong class="COMMAND">select</strong> по-умолчанию
                  использует в качестве приглашения к вводу (prompt) --
                  <code class="VARNAME">PS3</code> (<code class="PROMPT">#?</code> ), который легко
                  изменить.</p>

                  <div class="EXAMPLE">
                    <a name="EX31"></a>

                    <p><strong>Пример 10-29. Создание меню с помощью
                    select</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

PS3='Выберите ваш любимый овощ: ' # строка приглашения к вводу (prompt)

echo

select vegetable in "бобы" "морковь" "картофель" "лук" "брюква"
do
  echo
  echo "Вы предпочитаете $vegetable."
  echo ";-))"
  echo
  break  # если 'break' убрать, то получится бесконечный цикл.
done

exit 0
</pre>
                  </div>

                  <p>Если в операторе <strong class="COMMAND">select</strong> список <code class="USERINPUT"><strong>in <code class="REPLACEABLE"><em>list</em></code></strong></code>
                  не задан, то в качестве списка будет использоваться
                  список аргументов (<code class="VARNAME">$@</code>), передаваемый сценарию или
                  функции.</p>

                  <p>Сравните это с поведением оператора цикла</p>

                  <p><strong class="COMMAND">for</strong> <code class="REPLACEABLE"><em>variable</em></code> [in <code class="REPLACEABLE"><em>list</em></code>]</p>
                  в котором не задан список аргументов.<br>
                  <br>

                  <div class="EXAMPLE">
                    <a name="EX32"></a>

                    <p><strong>Пример 10-30. Создание меню с помощью
                    select в функции</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

PS3='Выберите ваш любимый овощ: '

echo

choice_of()
{
select vegetable
# список выбора [in list] отсутствует, поэтому 'select' использует входные аргументы функции.
do
  echo
  echo "Вы предпочитаете $vegetable."
  echo ";-))"
  echo
  break
done
}

choice_of бобы рис морковь редис томат шпинат
#         $1   $2  $3      $4    $5    $6
#         передача списка выбора в функцию choice_of()

exit 0
</pre>
                  </div>

                  <p>См. так же <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RESISTOR">Пример 34-3</a>.</p>
                </dd>
              </dl>
            </div>
          </div>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="INTERNAL"></a>Глава 11. Внутренние команды</h1>

          <p><a name="BUILTINREF"></a><em class="FIRSTTERM">Внутренняя</em> команда -- это <strong class="COMMAND">команда</strong>, которая встроена
          непосредственно в Bash. Команды делаются встроенными либо из
          соображений производительности -- встроенные команды
          исполняются быстрее, чем внешние, которые, как правило,
          запускаются в дочернем процессе, либо из-за необходимости
          прямого доступа к внутренним структурам командного
          интерпретатора.</p>

          <p><a name="FORKREF"></a></p>

          <table class="SIDEBAR" border="1" cellpadding="5">
            <tbody><tr>
              <td>
                <div class="SIDEBAR">
                  <a name="AEN5368"></a>

                  <p>Действие, когда какая либо команда или сама
                  командная оболочка инициирует (<span class="emphasis"><em class="EMPHASIS">порождает</em></span>) новый
                  подпроцесс, что бы выполнить какую либо работу,
                  называется <span class="emphasis"><em class="EMPHASIS">ветвлением</em></span> (<span class="emphasis"><em class="EMPHASIS">forking</em></span>) процесса.
                  Новый процесс называется <span class="QUOTE">"дочерним"</span> (или
                  "потомком"), а породивший его процесс --
                  <span class="QUOTE">"родительским"</span> (или
                  "предком"). В результате и <span class="emphasis"><em class="EMPHASIS">потомок</em></span> и <span class="emphasis"><em class="EMPHASIS">предок</em></span> продолжают
                  исполняться одновременно -- параллельно друг
                  другу.</p>

                  <p>В общем случае, <span class="emphasis"><em class="EMPHASIS">встроенные команды</em></span>
                  Bash, при исполнении внутри сценария, не порождают
                  новый подпроцесс, в то время как вызов внешних
                  команд, как правило, приводит к созданию нового
                  подпроцесса.</p>
                </div>
              </td>
            </tr>
          </tbody></table>

          <p>Внутренние команды могут иметь внешние аналоги. Например,
          внутренняя команда Bash -- <strong class="COMMAND">echo</strong> имеет внешний аналог <code class="FILENAME">/bin/echo</code> и их поведение практически
          идентично.</p>
<pre class="PROGRAMLISTING">#!/bin/bash

echo "Эта строка выводится внутренней командой \"echo\"."
/bin/echo "А эта строка выводится внешней командой the /bin/echo."
</pre>
          <br>
          <br>

          <p><a name="KEYWORDREF"></a><em class="FIRSTTERM">Ключевое слово</em> (keyword) -- это <span class="emphasis"><em class="EMPHASIS">зарезервированное</em></span> слово,
          синтаксический элемент (token) или оператор. Ключевые слова
          имеют специальное назначение для командного интерпретатора, и
          фактически являются элементами синтаксиса языка командной
          оболочки. В качестве примера можно привести <span class="QUOTE">"<span class="TOKEN">for</span>"</span>, <span class="QUOTE">"<span class="TOKEN">while</span>"</span>, <span class="QUOTE">"do"</span>, <span class="QUOTE">"<span class="TOKEN">!</span>"</span>, которые являются
          ключевыми (или зарезервированными) словами. Подобно <span class="emphasis"><em class="EMPHASIS">встроенным командам</em></span>, ключевые
          слова жестко зашиты в Bash, но в отличие от встроенных
          команд, ключевые слова не являются командами как таковыми,
          хотя при этом могут являться их составной частью. <a name="AEN5395" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN5395"><span class="footnote">[24]</span></a></p>

          <div class="VARIABLELIST">
            <p><strong><a name="INTIO1"></a>Ввод/вывод</strong></p>

            <dl>
              <dt><a name="ECHOREF"></a><strong class="COMMAND">echo</strong></dt>

              <dd>
                <p>выводит (на <code class="FILENAME">stdout</code>) выражение или содержимое
                переменной (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX9">Пример 4-1</a>).</p>
<pre class="PROGRAMLISTING">echo Hello
echo $a
</pre>
                <br>
                <br>

                <p>Для вывода экранированных символов, <strong class="COMMAND">echo</strong> требует наличие ключа
                <code class="OPTION">-e</code>. См. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ESCAPED">Пример 5-2</a>.</p>

                <p>Обычно, командв <strong class="COMMAND">echo</strong> выводит в конце символ
                перевода строки. Подавить вывод это символа можно
                ключом <code class="OPTION">-n</code>.</p>

                <div class="NOTE">
                  <table class="NOTE" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                      <td align="left" valign="top">
                        <p>Команда <strong class="COMMAND">echo</strong> может
                        использоваться для передачи информации по
                        конвейеру другим командам.</p>
<pre class="PROGRAMLISTING">if echo "$VAR" | grep -q txt   # if [[ $VAR = *txt* ]]
then
  echo "$VAR содержит подстроку \"txt\""
fi
</pre>
                        <br>
                        <br>
                      </td>
                    </tr>
                  </tbody></table>
                </div>

                <div class="NOTE">
                  <table class="NOTE" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                      <td align="left" valign="top">
                        <p>Кроме того, команда <strong class="COMMAND">echo</strong>, в комбинации с
                        <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COMMANDSUBREF">подстановкой команд</a>
                        может учавствовать в операции присвоения
                        значения переменной.</p>

                        <p><code class="USERINPUT"><strong>a=`echo
                        "HELLO" | tr A-Z
                        a-z`</strong></code></p>

                        <p>См. так же <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LOWERCASE">Пример 12-15</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX57">Пример 12-2</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MONTHLYPMT">Пример 12-32</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BASE">Пример 12-33</a>.</p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>

                <p>Следует запомнить, что команда <strong class="COMMAND">echo `command`</strong> удалит все
                символы перевода строки, которые будут выведены
                командой <code class="REPLACEABLE"><em>command</em></code>.</p>

                <p>Переменная <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IFSREF">$IFS</a> обычно содержит символ
                перевода строки <span class="TOKEN">\n</span>, как один из вариантов <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WHITESPACEREF">пробельного</a> символа. Bash
                разобьет вывод команды <code class="REPLACEABLE"><em>command</em></code>, по
                пробельным символам, на аргументы и передаст их команде
                <strong class="COMMAND">echo</strong>, которая выведет эти
                аргументы, разделенные пробелами.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>ls -l /usr/share/apps/kjezz/sounds</strong></code>
<code class="COMPUTEROUTPUT">-rw-r--r--    1 root     root         1407 Nov  7  2000 reflect.au
-rw-r--r--    1 root     root          362 Nov  7  2000 seconds.au</code>

<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo `ls -l /usr/share/apps/kjezz/sounds`</strong></code>
<code class="COMPUTEROUTPUT">total 40 -rw-r--r-- 1 root root 716 Nov 7 2000 reflect.au -rw-r--r-- 1 root root 362 Nov 7 2000 seconds.au</code>
             
</pre>
                <br>
                <br>

                <div class="NOTE">
                  <table class="NOTE" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                      <td align="left" valign="top">
                        <p>Это встроенная команда Bash и имеет внешний
                        аналог <code class="FILENAME">/bin/echo</code>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>type -a echo</strong></code>
<code class="COMPUTEROUTPUT">echo is a shell builtin
echo is /bin/echo</code>
             
</pre>
                        <br>
                        <br>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </dd>

              <dt><a name="PRINTFREF"></a><strong class="COMMAND">printf</strong></dt>

              <dd>
                <p><strong class="COMMAND">printf</strong> -- команда
                форматированного вывода, расширенный вариант команды
                <strong class="COMMAND">echo</strong> и ограниченный вариант
                библиотечной функции <code class="FUNCTION">printf()</code> в языке C, к тому же
                синтаксис их несколько отдичается друг от друга.</p>

                <p><strong class="COMMAND">printf</strong> <code class="REPLACEABLE"><em>format-string</em></code>... <code class="REPLACEABLE"><em>parameter</em></code>...</p>

                <p>Это встроенная команда Bash. Имеет внешний аналог
                <code class="FILENAME">/bin/printf</code> или <code class="FILENAME">/usr/bin/printf</code>. За более
                подробной информацией обращайтесь к страницам
                справочного руководства <strong class="COMMAND">man 1 printf</strong> по системным
                командам.</p>

                <div class="CAUTION">
                  <table class="CAUTION" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                      <td align="left" valign="top">
                        <p>Старые версии Bash могут не поддерживать
                        команду <strong class="COMMAND">printf</strong>.</p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>

                <div class="EXAMPLE">
                  <a name="EX47"></a>

                  <p><strong>Пример 11-1. printf в
                  действии</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# printf demo

# От переводчика:
# Считаю своим долгом напомнить, что в качестве разделителя дробной и целой
# частей в вещественных числах, может использоваться символ "запятая"
# (в русских локалях), поэтому данный сценарий может выдавать сообщение
# об ошибке (у меня так и произошло) при выводе числа PI.
# Тогда попробуйте заменить в определении числа PI десятичную точку
# на запятую -- это должно помочь. ;-)

PI=3,14159265358979
DecimalConstant=31373
Message1="Поздравляю,"
Message2="Землянин."

echo

printf "Число пи с точностью до 2 знака после запятой = %1.2f" $PI
echo
printf "Число пи с точностью до 9 знака после запятой = %1.9f" $PI  # Даже округляет правильно.

printf "\n"                                  # Перевод строки,

printf "Константа = \t%d\n" $DecimalConstant  # Вставлен символ табуляции (\t)

printf "%s %s \n" $Message1 $Message2

echo

# ==========================================#
# Эмуляция функции 'sprintf' в языке C.
# Запись форматированной строки в переменную.

echo

Pi12=$(printf "%1.12f" $PI)
echo "Число пи с точностью до 12 знака после запятой = $Pi12"

Msg=`printf "%s %s \n" $Message1 $Message2`
echo $Msg; echo $Msg

exit 0
</pre>
                </div>

                <p>Одно из полезных применений команды <strong class="COMMAND">printf</strong> -- форматированный
                вывод сообщений об ошибках</p>
<pre class="PROGRAMLISTING">E_BADDIR=65

var=nonexistent_directory

error()
{
  printf "$@" &gt;&amp;2
  # Форматированный вывод аргументов на stderr.
  echo
  exit $E_BADDIR
}

cd $var || error $"Невозможно перейти в каталог %s." "$var"

# Спасибо S.C.
</pre>
                <br>
                <br>
              </dd>

              <dt><a name="READREF"></a><strong class="COMMAND">read</strong></dt>

              <dd>
                <p><span class="QUOTE">"Читает"</span> значение
                переменной с устройства стандартного ввода -- <code class="FILENAME">stdin</code>, в интерактивном режиме
                это означает клавиатуру. Ключ <code class="OPTION">-a</code> позволяет записывать значения в
                массивы (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX67">Пример 25-3</a>).</p>

                <div class="EXAMPLE">
                  <a name="EX36"></a>

                  <p><strong>Пример 11-2. Ввод значений переменных с
                  помощью read</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

echo -n "дите значение переменной 'var1': "
# Ключ -n подавляет вывод символа перевода строки.

read var1
# Обратите внимание -- перед именем переменной отсутствует символ '$'.

echo "var1 = $var1"


echo

# Одной командой 'read' можно вводить несколько переменных.
echo -n "дите значения для переменных 'var2' и 'var3' (через пробел или табуляцию): "
read var2 var3
echo "var2 = $var2      var3 = $var3"
# Если было введено значение только одной переменной, то вторая останется "пустой".

exit 0
</pre>
                </div>

                <p>Если команде <strong class="COMMAND">read</strong> не была передано ни
                одной переменной, то ввод будет осуществлен в
                переменную <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REPLYREF">$REPLY</a>.</p>

                <div class="EXAMPLE">
                  <a name="READNOVAR"></a>

                  <p><strong>Пример 11-3. Пример использования команды
                  read без указания переменной для ввода</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

echo

# -------------------------- #
# Первый блок кода.
echo -n "Введите значение: "
read var
echo "\"var\" = "$var""
# Здесь нет ничего неожиданного.
# -------------------------- #

echo

echo -n "Введите другое значение: "
read           #  Команда 'read' употребляется без указания переменной для ввода,
               #+ тем не менее...
               #+ По-умолчанию ввод осуществляется в переменную $REPLY.
var="$REPLY"
echo "\"var\" = "$var""
# Эта часть сценария эквивалентна первому блоку, выделенному выше.

echo

exit 0
</pre>
                </div>

                <p>Обычно, при вводе в окне терминала с помощью команды
                "read", символ <code class="USERINPUT"><strong>\</strong></code> служит для
                экранирования символа перевода строки. Ключ <code class="OPTION">-r</code> заставляет интерпретировать
                символ <code class="USERINPUT"><strong>\</strong></code> как обычный
                символ.</p>

                <div class="EXAMPLE">
                  <a name="READR"></a>

                  <p><strong>Пример 11-4. Ввод многострочного текста с
                  помощью read</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

echo

echo "Введите строку, завершающуюся символом \\, и нажмите ENTER."
echo "Затем введите вторую строку, и снова нажмите ENTER."
read var1     # При чтении, символ "\" экранирует перевод строки.
              #     первая строка \
              #     вторая строка

echo "var1 = $var1"
#     var1 = первая строка вторая строка

# После ввода каждой строки, завершающейся символом "\",
# вы можете продолжать ввод на другой строке.

echo; echo

echo "Введите другую строку, завершающуюся символом \\, и нажмите ENTER."
read -r var2  # Ключ -r заставляет команду "read" воспринимать "\"
              # как обычный символ.
              #     первая строка \

echo "var2 = $var2"
#     var2 = первая строка \

# Ввод данных прекращается сразу же после первого нажатия на клавишу ENTER.

echo 

exit 0
</pre>
                </div>

                <p>Команда <strong class="COMMAND">read</strong> имеет ряд очень
                любопытных опций, которые позволяют выводить подсказку
                - приглашение ко вводу (prompt), и даже читать данные
                не дожидаясь нажатия на клавишу <strong class="KEYCAP">ENTER</strong>.</p>
<pre class="PROGRAMLISTING"># Чтение данных, не дожидаясь нажатия на клавишу ENTER.

read -s -n1 -p "Нажмите клавишу " keypress
echo; echo "Была нажата клавиша "\"$keypress\""."

# -s   -- подавляет эхо-вывод, т.е. ввод с клавиатуры не отображается на экране.
# -n N -- ввод завершается автоматически, сразу же после ввода N-го символа.
# -p   -- задает вид строки подсказки - приглашения к вводу (prompt).

# Использование этих ключей немного осложняется тем, что они должны следовать в определенном порядке.
</pre>
                <br>
                <br>

                <p>Ключ <code class="OPTION">-n</code>, кроме всего прочего, позволяет
                команде <strong class="COMMAND">read</strong> обнаруживать нажатие
                <span class="emphasis"><em class="EMPHASIS">курсорных</em></span> и некоторых
                других служебных клавиш.</p>

                <div class="EXAMPLE">
                  <a name="ARROWDETECT"></a>

                  <p><strong>Пример 11-5. Обнаружение нажатия на
                  курсорные клавиши</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# arrow-detect.sh: Обнаружение нажатия на курсорные клавиши, и не только...
# Спасибо Sandro Magi за то что показал мне -- как.

# --------------------------------------------
# Коды клавиш.
arrowup='\[A'
arrowdown='\[B'
arrowrt='\[C'
arrowleft='\[D'
insert='\[2'
delete='\[3'
# --------------------------------------------

SUCCESS=0
OTHER=65

echo -n "Нажмите на клавишу...  "
# Может потребоваться нажать на ENTER, если была нажата клавиша
# не входящая в список выше.
read -n3 key                      # Прочитать 3 символа.

echo -n "$key" | grep "$arrowup"  #Определение нажатой клавиши.
if [ "$?" -eq $SUCCESS ]
then
  echo "Нажата клавиша \"."
  exit $SUCCESS
fi

echo -n "$key" | grep "$arrowdown"
if [ "$?" -eq $SUCCESS ]
then
  echo "Нажата клавиша \"
  exit $SUCCESS
fi

echo -n "$key" | grep "$arrowrt"
if [ "$?" -eq $SUCCESS ]
then
  echo "Нажата клавиша \"О\"."
  exit $SUCCESS
fi

echo -n "$key" | grep "$arrowleft"
if [ "$?" -eq $SUCCESS ]
then
  echo "Нажата клавиша \"."
  exit $SUCCESS
fi

echo -n "$key" | grep "$insert"
if [ "$?" -eq $SUCCESS ]
then
  echo "Нажата клавиша \"Insert\"."
  exit $SUCCESS
fi

echo -n "$key" | grep "$delete"
if [ "$?" -eq $SUCCESS ]
then
  echo "Нажата клавиша \"Delete\"."
  exit $SUCCESS
fi


echo " Нажата какая-то другая клавиша."

exit $OTHER

#  Упражнения:
#  ---------
#  1) Упростите сценарий, заменив множество if-ов
#+    одной конструкцией 'case'.
#  2) Добавьте определение нажатий на клавиши "Home", "End", "PgUp" и "PgDn".
</pre>
                </div>

                <p>Ключ <code class="OPTION">-t</code> позволяет ограничивать время
                ожидания ввода командой <strong class="COMMAND">read</strong> (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TOUT">Пример 9-4</a>).</p>

                <p>Команда <strong class="COMMAND">read</strong> может считывать значения
                для переменных из файла, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IOREDIRREF">перенаправленного</a> на <code class="FILENAME">stdin</code>. Если файл содержит не
                одну строку, то переменной будет присвоена только
                первая строка. Если команде <strong class="COMMAND">read</strong> будет передано несколько
                переменных, то первая строка файла будет разбита, по
                пробелам, на несколько подстрок, каждая из которых
                будет записана в свою переменную. Будьте осторожны!</p>

                <div class="EXAMPLE">
                  <a name="READREDIR"></a>

                  <p><strong>Пример 11-6. Чтение командой read из файла
                  через <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IOREDIRREF">перенаправление</a></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

read var1 &lt;data-file
echo "var1 = $var1"
# Первая строка из "data-file" целиком записывается в переменную var1

read var2 var3 &lt;data-file
echo "var2 = $var2   var3 = $var3"
# Обратите внимание!
# Поведение команды "read" далеко от ожидаемого!
# 1) Произошел возврат к началу файла.
# 2) Вместо того, чтобы последовательно читать строки из файла,
#    по числу переменных, первая строка файла была разбита на подстроки,
#    разделенные пробелами, которые и были записаны в переменные.
# 3) В последнюю переменную была записана вся оставшаяся часть строки.
# 4) Если команде "read" будет передано большее число переменных, чем подстрок
#    в первой строке файла, то последние переменные останутся "пустыми".

echo "------------------------------------------------"

# Эта проблема легко разрешается с помощью цикла:
while read line
do
  echo "$line"
done &lt;data-file
# Спасибо Heiner Steven за разъяснения.

echo "------------------------------------------------"

# Разбор строки, разделенной на поля
# Для задания разделителя полей, используется переменная $IFS,

echo "Список всех пользователей:"
OIFS=$IFS; IFS=:       # В файле /etc/passwd, в качестве разделителя полей
                       # используется символ ":" .
while read name passwd uid gid fullname ignore
do
  echo "$name ($fullname)"
done &lt;/etc/passwd      # перенаправление ввода.
IFS=$OIFS              # Восстановление предыдущего состояния переменной $IFS.
# Эту часть кода написал Heiner Steven.



#  Если переменная $IFS устанавливается внутри цикла,
#+ то отпадает необходимость сохранения ее первоначального значения
#+ во временной переменной.
#  Спасибо Dim Segebart за разъяснения.
echo "------------------------------------------------"
echo "Список всех пользователей:"

while IFS=: read name passwd uid gid fullname ignore
do
  echo "$name ($fullname)"
done &lt;/etc/passwd   # перенаправление ввода.

echo
echo "Значение переменной \$IFS осталось прежним: $IFS"

exit 0
</pre>
                </div>

                <div class="NOTE">
                  <table class="NOTE" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                      <td align="left" valign="top">
                        <p>Передача информации, выводимой командой <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ECHOREF">echo</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PIPEREF">по конвейеру</a> команде
                        <strong class="COMMAND">read</strong>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BADREAD0">будет вызывать
                        ошибку</a>.</p>

                        <p>Тем не менее, передача данных по конвейеру
                        от <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CATREF">cat</a>, кажется
                        срабатывает.</p>
<pre class="PROGRAMLISTING">cat file1 file2 |
while read line
do
echo $line
done
</pre>
                        <br>
                        <br>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </dd>
            </dl>
          </div>

          <div class="VARIABLELIST">
            <p><strong><a name="INTFILESYSTEM1"></a>Файловая система</strong></p>

            <dl>
              <dt><strong class="COMMAND">cd</strong></dt>

              <dd>
                <p>Уже знакомая нам команда <strong class="COMMAND">cd</strong>, изменяющая текущий
                каталог, может быть использована в случаях, когда
                некоторую команду необходимо запустить только находясь
                в определенном каталоге.</p>
<pre class="PROGRAMLISTING">(cd /source/directory &amp;&amp; tar cf - . ) | (cd /dest/directory &amp;&amp; tar xpvf -)
</pre>
                [взято из <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COXEX">упоминавшегося ранее</a> примера]<br>
                <br>

                <p>Команда <strong class="COMMAND">cd</strong> с ключом <code class="OPTION">-P</code> (physical) игнорирует
                символические ссылки.</p>

                <p>Команда <span class="QUOTE">"<strong class="COMMAND">cd -</strong>"</span> выполняет
                переход в каталог <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#OLDPWD">$OLDPWD</a> -- предыдущий рабочий
                каталог.</p>

                <p><a name="DOUBLESLAS"></a></p>

                <div class="CAUTION">
                  <table class="CAUTION" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                      <td align="left" valign="top">
                        <p>Неожиданным образом выполняется команда
                        <strong class="COMMAND">cd</strong>, если ей передать,
                        в качестве каталога назначения, два слэша.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>cd //</strong></code>
<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>pwd</strong></code>
<code class="COMPUTEROUTPUT">//</code>
             
</pre>
                        Само собой разумеется, это должен был бы быть
                        каталог <code class="COMPUTEROUTPUT">/</code>. Эта проблема
                        наблюдается как в командной строке, так и в
                        сценариях.<br>
                        <br>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </dd>

              <dt><a name="PWD2REF"></a><strong class="COMMAND">pwd</strong></dt>

              <dd>
                <p>Выводит название текущего рабочего каталога (Print
                Working Directory) (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX37">Пример 11-7</a>). Кроме того, имя
                текущего каталога хранится во внутренней переменной <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PWDREF">$PWD</a>.</p>
              </dd>

              <dt><a name="DIRSD"></a><strong class="COMMAND">pushd</strong>, <strong class="COMMAND">popd</strong>, <strong class="COMMAND">dirs</strong></dt>

              <dd>
                <p>Этот набор команд является составной частью
                механизма "закладок" на каталоги и позволяет
                перемещаться по каталогам вперед и назад в заданном
                порядке. Для хранения имен каталогов используется стек
                (LIFO -- "последний вошел, первый
                вышел").</p>

                <p><a name="PUSHDREF"></a><code class="USERINPUT"><strong>pushd dir-name</strong></code>
                -- помещает имя текущего каталога в стек и осуществляет
                переход в каталог <code class="REPLACEABLE"><em>dir-name</em></code>.</p>

                <p><a name="POPDREF"></a><strong class="COMMAND">popd</strong> -- выталкивает,
                находящееся на вершине стека, имя каталога и
                одновременно осуществляет переход в каталог,
                оказавшийся на врешине стека.</p>

                <p><strong class="COMMAND">dirs</strong> -- выводит содержимое
                стека каталогов (сравните с переменной <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DIRSTACKREF">$DIRSTACK</a>). В случае успеха,
                обе команды -- <strong class="COMMAND">pushd</strong> и <strong class="COMMAND">popd</strong> автоматически вызывают
                <strong class="COMMAND">dirs</strong>.</p>

                <p>Эти команды могут оказаться весьма полезными, когда
                в сценарии нужно производить частую смену каталогов, но
                при этом не хочется жестко "зашивать" имена
                каталогов. Обратите внимание: содержимое стека
                каталогов постоянно хранится в переменной-массиве --
                <code class="VARNAME">$DIRSTACK</code>.</p>

                <div class="EXAMPLE">
                  <a name="EX37"></a>

                  <p><strong>Пример 11-7. Смена текущего
                  каталога</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

dir1=/usr/local
dir2=/var/spool

pushd $dir1
# Команда 'dirs' будет вызвана автоматически (на stdout будет выведено содержимое стека).
echo "Выполнен переход в каталог `pwd`." # Обратные одиночные кавычки.

# Теперь можно выполнить какие либо действия в каталоге 'dir1'.
pushd $dir2
echo "Выполнен переход в каталог `pwd`."

# Теперь можно выполнить какие либо действия в каталоге 'dir2'.
echo "На вершине стека находится: $DIRSTACK."
popd
echo "Возврат в каталог `pwd`."

# Теперь можно выполнить какие либо действия в каталоге 'dir1'.
popd
echo "Возврат в первоначальный рабочий каталог `pwd`."

exit 0
</pre>
                </div>
              </dd>
            </dl>
          </div>

          <div class="VARIABLELIST">
            <p><strong><a name="INTVAR1"></a>Переменные</strong></p>

            <dl>
              <dt><a name="LETREF"></a><strong class="COMMAND">let</strong></dt>

              <dd>
                <p>Команда <strong class="COMMAND">let</strong> производит арифметические
                операции над переменными. В большинстве случаев, ее
                можно считать упрощенным вариантом команды <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXPRREF">expr</a>.</p>

                <div class="EXAMPLE">
                  <a name="EX46"></a>

                  <p><strong>Пример 11-8. Команда let, арифметические
                  операции.</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

echo

let a=11          # То же, что и 'a=11'
let a=a+5         # Эквивалентно "a = a + 5"
                  # (Двойные кавычки и дополнительные пробелы делают код более удобочитаемым)
echo "11 + 5 = $a"

let "a &lt;&lt;= 3"     # Эквивалентно  let "a = a &lt;&lt; 3"
echo "\"\$a\" (=16) после сдвига влево на 3 разряда = $a"

let "a /= 4"      # Эквивалентно let "a = a / 4"
echo "128 / 4 = $a"

let "a -= 5"      # Эквивалентно let "a = a - 5"
echo "32 - 5 = $a"

let "a = a * 10"  # Эквивалентно let "a = a * 10"
echo "27 * 10 = $a"

let "a %= 8"      # Эквивалентно let "a = a % 8"
echo "270 mod 8 = $a  (270 / 8 = 33, остаток = $a)"

echo

exit 0
</pre>
                </div>
              </dd>

              <dt><a name="EVALREF"></a><strong class="COMMAND">eval</strong></dt>

              <dd>
                <p><code class="USERINPUT"><strong>eval arg1 [arg2] ...
                [argN]</strong></code></p>

                <p>Транслирует список аргументов, из списка, в
                команды.</p>

                <div class="EXAMPLE">
                  <a name="EX43"></a>

                  <p><strong>Пример 11-9. Демонстрация команды
                  eval</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

y=`eval ls -l`  # Подобно y=`ls -l`
echo $y         # но символы перевода строки не выводятся, поскольку имя переменной не в кавычках.
echo
echo "$y"       # Если имя переменной записать в кавычках -- символы перевода строки сохраняются.

echo; echo

y=`eval df`     # Аналогично y=`df`
echo $y         # но без символов перевода строки.

#  Когда производится подавление вывода символов LF (перевод строки), то анализ
#+ результатов различными утилитами, такими как awk, можно сделать проще.

exit 0
</pre>
                </div>

                <div class="EXAMPLE">
                  <a name="EX44"></a>

                  <p><strong>Пример 11-10. Принудительное завершение
                  сеанса</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

y=`eval ps ax | sed -n '/ppp/p' | awk '{ print $1 }'`
# Выяснить PID процесса 'ppp'.

kill -9 $y   # "Прихлопнуть" его

# Предыдущие строки можно заменить одной строкой
#  kill -9 `ps ax | awk '/ppp/ { print $1 }'


chmod 666 /dev/ttyS3
# Завершенный, по сигналу SIGKILL, ppp изменяет права доступа
# к последовательному порту. Вернуть их в первоначальное состояние.

rm /var/lock/LCK..ttyS3   # Удалить lock-файл последовательного порта.

exit 0
</pre>
                </div>

                <div class="EXAMPLE">
                  <a name="ROT14"></a>

                  <p><strong>Пример 11-11. Шифрование по алгоритму
                  <span class="QUOTE">"rot13"</span></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Реализация алгоритма шифрования "rot13" с помощью 'eval'.
# Сравните со сценарием "rot13.sh".

setvar_rot_13()              # Криптование по алгоритму "rot13"
{
  local varname=$1 varvalue=$2
  eval $varname='$(echo "$varvalue" | tr a-z n-za-m)'
}


setvar_rot_13 var "foobar"   # Пропустить слово "foobar" через rot13.
echo $var                    # sbbone

echo $var | tr a-z n-za-m    # foobar
                             # Расшифровывание.

# Пример предоставил Stephane Chazelas.

exit 0
</pre>
                </div>

                <p>Rory Winston представил следующий пример, как
                образец практического использования команды <strong class="COMMAND">eval</strong>.</p>

                <div class="EXAMPLE">
                  <a name="EVALEX"></a>

                  <p><strong>Пример 11-12. Замена имени переменной на
                  ее значение, в исходном тексте программы на языке
                  Perl, с помощью eval</strong></p>
<pre class="PROGRAMLISTING">В программе "test.pl", на языке Perl:
        ...
        my $WEBROOT = &lt;WEBROOT_PATH&gt;;
        ...

Эта попытка подстановки значения переменной вместо ее имени:
        $export WEBROOT_PATH=/usr/local/webroot
        $sed 's/&lt;WEBROOT_PATH&gt;/$WEBROOT_PATH/' &lt; test.pl &gt; out

даст такой результат:
        my $WEBROOT = $WEBROOT_PATH;

Тем не менее:
        $export WEBROOT_PATH=/usr/local/webroot
        $eval sed 's/&lt;WEBROOT_PATH&gt;/$WEBROOT_PATH/' &lt; test.pl &gt; out
#        ====

Этот вариант дал желаемый результат -- имя переменной, в тексте программы,
благополучно было заменено на ее значение:
        my $WEBROOT = /usr/local/webroot
</pre>
                </div>

                <div class="CAUTION">
                  <table class="CAUTION" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                      <td align="left" valign="top">
                        <p>Команда <strong class="COMMAND">eval</strong> может быть
                        небезопасна. Если существует приемлемая
                        альтернатива, то желательно воздерживаться от
                        использования <strong class="COMMAND">eval</strong>. Так, <code class="USERINPUT"><strong>eval
                        $COMMANDS</strong></code> исполняет код, который
                        записан в переменную <code class="REPLACEABLE"><em>COMMANDS</em></code>,
                        которая, в свою очередь, может содержать весьма
                        неприятные сюрпризы, например <strong class="COMMAND">rm -rf *</strong>.
                        Использование команды <strong class="COMMAND">eval</strong>, для исполнения
                        кода неизвестного происхождения, крайне
                        опасно.</p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </dd>

              <dt><a name="SETREF"></a><strong class="COMMAND">set</strong></dt>

              <dd>
                <p>Команда <strong class="COMMAND">set</strong> изменяет значения
                внутренних переменных сценария. Она может
                использоваться для переключения <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#OPTIONSREF">опций (ключей, флагов)</a>,
                определяющих поведение скрипта. Еще одно применение --
                сброс/установка <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#POSPARAMREF">позиционных параметров
                (аргументов)</a>, значения которых будут восприняты как
                результат работы команды (<code class="USERINPUT"><strong>set
                `command`</strong></code>).</p>

                <div class="EXAMPLE">
                  <a name="EX34"></a>

                  <p><strong>Пример 11-13. Установка значений
                  аргументов с помощью команды set</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# script "set-test"

# Вызовите сценарий с тремя аргументами командной строки,
# например: "./set-test one two three".

echo
echo "Аргументы перед вызовом set \`uname -a\` :"
echo "Аргумент #1 = $1"
echo "Аргумент #2 = $2"
echo "Аргумент #3 = $3"


set `uname -a` # Изменение аргументов
               # значения которых берутся из результата работы `uname -a`

echo $_

echo "Аргументы после вызова set \`uname -a\` :"
#  $1, $2, $3 и т.д. будут переустановлены в соответствии с выводом
#+ команды `uname -a`
echo "Поле #1 'uname -a' = $1"
echo "Поле #2 'uname -a' = $2"
echo "Поле #3 'uname -a' = $3"
echo ---
echo $_        # ---
echo

exit 0
</pre>
                </div>

                <p>Вызов <strong class="COMMAND">set</strong> без параметров просто
                выводит список инициализированных переменных <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ENVREF">окружения</a>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>set</strong></code>
<code class="COMPUTEROUTPUT">AUTHORCOPY=/home/bozo/posts
 BASH=/bin/bash
 BASH_VERSION=$'2.05.8(1)-release'
 ...
 XAUTHORITY=/home/bozo/.Xauthority
 _=/etc/bashrc
 variable22=abc
 variable23=xzy</code>
             
</pre>
                <br>
                <br>

                <p>Если команда <strong class="COMMAND">set</strong> используется с ключом
                <span class="QUOTE">"<code class="OPTION">--</code>"</span>, после которого
                следует переменная, то значение переменной переносится
                в позиционные параметры (аргументы). Если имя
                переменной отсутствует, то эта команда приводит к
                сбросу позиционных параметров.</p>

                <div class="EXAMPLE">
                  <a name="SETPOS"></a>

                  <p><strong>Пример 11-14. Изменение значений
                  позиционных параметров (аргументов)</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

variable="one two three four five"

set -- $variable
# Значения позиционных параметров берутся из "$variable".

first_param=$1
second_param=$2
shift; shift        # сдвиг двух первых параметров.
remaining_params="$*"

echo
echo "первый параметр = $first_param"            # one
echo "второй параметр = $second_param"           # two
echo "остальные параметры = $remaining_params"   # three four five

echo; echo

# Снова.
set -- $variable
first_param=$1
second_param=$2
echo "первый параметр = $first_param"             # one
echo "второй параметр = $second_param"            # two

# ======================================================

set --
# Позиционные параметры сбрасываются, если не задано имя переменной.

first_param=$1
second_param=$2
echo "первый параметр = $first_param"            # (пустое значение)
echo "второй параметр = $second_param"           # (пустое значение)

exit 0
</pre>
                </div>

                <p>См. так же <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX22A">Пример 10-2</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX33A">Пример 12-40</a>.</p>
              </dd>

              <dt><a name="UNSETREF"></a><strong class="COMMAND">unset</strong></dt>

              <dd>
                <p>Команда <strong class="COMMAND">unset</strong> удаляет переменную,
                фактически -- устанавливает ее значение в <span class="emphasis"><em class="EMPHASIS">null</em></span>. Обратите внимание:
                эта команда не может сбрасывать позиционные параметры
                (аргументы).</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>unset PATH</strong></code>

<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo $PATH</strong></code>
<code class="COMPUTEROUTPUT">
</code>
<code class="PROMPT">bash$</code>
</pre>
                <br>
                <br>

                <div class="EXAMPLE">
                  <a name="UNS"></a>

                  <p><strong>Пример 11-15. <span class="QUOTE">"Сброс"</span>
                  переменной</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# unset.sh: Сброс переменной.

variable=hello                       # Инициализация.
echo "variable = $variable"

unset variable                       # Сброс.
                                     # Тот же эффект дает   variable=
echo "(unset) variable = $variable"  # $variable = null.

exit 0
</pre>
                </div>
              </dd>

              <dt><a name="EXPORTREF"></a><strong class="COMMAND">export</strong></dt>

              <dd>
                <p>Команда <strong class="COMMAND">export</strong> экспортирует
                переменную, делая ее доступной дочерним процессам. К
                сожалению, невозможно экспортировать переменную
                родительскому процессу. В качестве примера
                использования команды <strong class="COMMAND">export</strong> можно привести <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FILESREF1">сценарии инициализации системы</a>,
                вызываемые в процессе загрузки, которые инициализируют
                и экспортируют <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ENVREF">переменные окружения</a>, делая их
                доступными для пользовательских процессов.</p>

                <div class="EXAMPLE">
                  <a name="COLTOTALER3"></a>

                  <p><strong>Пример 11-16. Передача переменных во
                  вложенный сценарий <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AWKREF">awk</a>, с помощью
                  export</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# Еще одна версия сценария "column totaler" (col-totaler.sh)
# который суммирует заданную колонку (чисел) в заданном файле.
# Здесь используются переменные окружения, которые передаются сценарию 'awk'.

ARGS=2
E_WRONGARGS=65

if [ $# -ne "$ARGS" ] # Проверка количества входных аргументов.
then
   echo "Порядок использования: `basename $0` filename column-number"
   exit $E_WRONGARGS
fi

filename=$1
column_number=$2

#===== До этой строки идентично первоначальному варианту сценария =====#

export column_number
# Экспорт номера столбца.


# Начало awk-сценария.
# ------------------------------------------------
awk '{ total += $ENVIRON["column_number"]
}
END { print total }' $filename
# ------------------------------------------------
# Конец awk-сценария.


# Спасибо Stephane Chazelas.

exit 0
</pre>
                </div>

                <div class="TIP">
                  <table class="TIP" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/tip.gif" hspace="5" alt="Tip"></td>

                      <td align="left" valign="top">
                        <p>Допускается объединение инициализации и
                        экспорта переменной в одну инструкцию: <strong class="COMMAND">export var1=xxx</strong>.</p>

                        <p>Однако, как заметил Greg Keraunen, в
                        некоторых ситуациях такая комбинация может
                        давать иной результат, нежели раздельная
                        инициализация и экспорт.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>export var=(a b); echo ${var[0]}</strong></code>
<code class="COMPUTEROUTPUT">(a b)</code>
<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>var=(a b); export var; echo ${var[0]}</strong></code>
<code class="COMPUTEROUTPUT">a</code>
             
</pre>
                        <br>
                        <br>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </dd>

              <dt><strong class="COMMAND">declare</strong>, <strong class="COMMAND">typeset</strong></dt>

              <dd>
                <p>Команды <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DECLAREREF">declare</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DECLAREREF">typeset</a> задают и/или
                накладывают ограничения на переменные.</p>
              </dd>

              <dt><strong class="COMMAND">readonly</strong></dt>

              <dd>
                <p>То же самое, что и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DECLAREREF">declare -r</a>, делает переменную
                доступной только для чтения, т.е. переменная становится
                подобна константе. При попытке изменить значение такой
                переменной выводится сообщение об ошибке. Эта команда
                может расцениваться как квалификатор типа <strong class="COMMAND">const</strong> в языке C.</p>
              </dd>

              <dt><a name="GETOPTSX"></a><strong class="COMMAND">getopts</strong></dt>

              <dd>
                <p>Мощный инструмент, используемый для разбора
                аргументов, передаваемых сценарию из командной строки.
                Это встроенная команда Bash, но имеется и ее
                "внешний" аналог <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GETOPTY">/usr/bin/getopt</a>, а так же
                программистам, пишущим на C, хорошо знакома похожая
                библиотечная функция <strong class="COMMAND">getopt</strong>. Она позволяет
                обрабатывать серии опций, объединенных в один аргумент
                <a name="AEN5877" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN5877"><span class="footnote">[25]</span></a> и дополнительные
                аргументы, передаваемые сценарию (например, <code class="USERINPUT"><strong>scriptname -abc -e
                /usr/local</strong></code>).</p>

                <p>С командой <strong class="COMMAND">getopts</strong> очень тесно
                взаимосвязаны скрытые переменные. <code class="VARNAME">$OPTIND</code> -- указатель на аргумент
                (<em class="WORDASWORD">OPTion INDex</em>) и <code class="VARNAME">$OPTARG</code> (<em class="WORDASWORD">OPTion ARGument</em>) --
                дополнительный аргумент опции. Символ двоеточия,
                следующий за именем опции, указывает на то, что она
                имеет дополнительный аргумент.</p>

                <p>Обычно <strong class="COMMAND">getopts</strong> упаковывается в цикл
                <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WHILELOOPREF">while</a>, в каждом проходе цикла
                извлекается очередная опция и ее аргумент (если он
                имеется), обрабатывается, затем уменьшается на 1
                скрытая переменная <code class="VARNAME">$OPTIND</code> и выполняется переход к
                началу новой итерации.</p>

                <div class="NOTE">
                  <table class="NOTE" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                      <td align="left" valign="top">
                        <ol type="1">
                          <li>
                            <p>Опциям (ключам), передаваемым в сценарий
                            из командной строки, должен предшествовать
                            символ "минус" (<code class="OPTION">-</code>) или
                            "плюс" (<code class="OPTION">+</code>). Этот префикс (<code class="OPTION">-</code> или <code class="OPTION">+</code>) позволяет <strong class="COMMAND">getopts</strong> отличать
                            опции (ключи) от прочих аргументов.
                            Фактически, <strong class="COMMAND">getopts</strong> не будет
                            обрабатывать аргументы, если им не
                            предшествует символ <code class="OPTION">-</code> или <code class="OPTION">+</code>, выделение опций
                            будет прекращено как только встретится
                            первый аргумент.</p>
                          </li>

                          <li>
                            <p>Типичная конструкция цикла <strong class="COMMAND">while</strong> с <strong class="COMMAND">getopts</strong> несколько
                            отличается от стандартной из-за отсутствия
                            квадратных скобок, проверяющих условие
                            продолжения цикла.</p>
                          </li>

                          <li>
                            <p>Пример <strong class="COMMAND">getopts</strong>,
                            заменившей устаревшую, и не такую мощную,
                            внешнюю команду <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GETOPTY">getopt</a>.</p>
                          </li>
                        </ol>
                        <br>
                        <br>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
<pre class="PROGRAMLISTING">while getopts ":abcde:fg" Option
# Начальное объявление цикла анализа опций.
# a, b, c, d, e, f, g -- это возможные опции (ключи).
# Символ : после опции 'e' указывает на то, что с данной опцией может идти
# дополнительный аргумент.
do
  case $Option in
    a ) # Действия, предусмотренные опцией 'a'.
    b ) # Действия, предусмотренные опцией 'b'.
    ...
    e)  # Действия, предусмотренные опцией 'e', а так же необходимо обработать $OPTARG,
        # в которой находится дополнительный аргумент этой опции.
    ...
    g ) # Действия, предусмотренные опцией 'g'.
  esac
done
shift $(($OPTIND - 1))
# Перейти к следующей опции.

# Все не так сложно, как может показаться ;-)
             
</pre>
                <br>
                <br>

                <div class="EXAMPLE">
                  <a name="EX33"></a>

                  <p><strong>Пример 11-17. Прием опций/аргументов,
                  передаваемых сценарию, с помощью getopts</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# ex33.sh

# Обработка опций командной строки с помощью 'getopts'.

# Попробуйте вызвать этот сценарий как:
# 'scriptname -mn'
# 'scriptname -oq qOption' (qOption может быть любой произвольной строкой.)
# 'scriptname -qXXX -r'
#
# 'scriptname -qr'    - Неожиданный результат: "r" будет воспринят как дополнительный аргумент опции "q"
# 'scriptname -q -r'  - То же самое, что и выше
#  Если опция ожидает дополнительный аргумент ("flag:"), то следующий параметр
#  в командной строке, будет воспринят как дополнительный аргумент этой опции.

NO_ARGS=0
E_OPTERROR=65

if [ $# -eq "$NO_ARGS" ]  # Сценарий вызван без аргументов?
then
  echo "Порядок использования: `basename $0` options (-mnopqrs)"
  exit $E_OPTERROR        # Если аргументы отсутствуют -- выход с сообщением
                          # о порядке использования скрипта
fi
# Порядок использования: scriptname -options
# Обратите внимание: дефис (-) обязателен


while getopts ":mnopq:rs" Option
do
echo $OPTIND
  case $Option in
    m     ) echo "Сценарий #1: ключ -m-";;
    n | o ) echo "Сценарий #2: ключ -$Option-";;
    p     ) echo "Сценарий #3: ключ -p-";;
    q     ) echo "Сценарий #4: ключ -q-, с аргументом \"$OPTARG\"";;
    # Обратите внимание: с ключом 'q' должен передаваться дополнительный аргумент,
    # в противном случае отработает выбор "по-умолчанию".
    r | s ) echo "Сценарий #5: ключ -$Option-"'';;
    *     ) echo "Выбран недопустимый ключ.";;   # ПО-УМОЛЧАНИЮ
  esac
done
shift $(($OPTIND - 1))
# Переход к очередному параметру командной строки.

exit 0
</pre>
                </div>
              </dd>
            </dl>
          </div>

          <div class="VARIABLELIST">
            <p><strong><a name="INTSCRBEH1"></a>Управление сценарием</strong></p>

            <dl>
              <dt><a name="SOURCEREF"></a><strong class="COMMAND">source</strong>, <span class="TOKEN">.</span> (<a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DOTREF">точка</a>)</dt>

              <dd>
                <p>Когда эта команда вызывается из командной строки, то
                это приводит к запуску указанного сценария. Внутри
                сценария, команда <code class="USERINPUT"><strong>source
                file-name</strong></code> загружает файл <code class="FILENAME">file-name</code>. Таким образом она
                очень напоминает директиву препроцессора языка C/C++ --
                "#include". Может найти применение в
                ситуациях, когда несколько сценариев пользуются одним
                файлом с данными или библиотекой функций.</p>

                <div class="EXAMPLE">
                  <a name="EX38"></a>

                  <p><strong>Пример 11-18. <span class="QUOTE">"Подключение"</span>
                  внешнего файла</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

. data-file    # Загрузка файла с данными.
# Тот же эффект дает "source data-file", но этот вариант более переносим.

#  Файл "data-file" должен находиться в текущем каталоге,
#+ т.к. путь к нему не указан.

# Теперь, выведем некоторые переменные из этого файла.

echo "variable1 (из data-file) = $variable1"
echo "variable3 (из data-file) = $variable3"

let "sum = $variable2 + $variable4"
echo "Сумма variable2 + variable4 (из data-file) = $sum"
echo "message1 (из data-file):  \"$message1\""
# Обратите внимание:             кавычки экранированы

print_message Вызвана функция вывода сообщений, находящаяся в data-file.


exit 0
</pre>

                  <p>Файл <code class="FILENAME">data-file</code> для <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX38">Пример 11-18</a>, представленного выше,
                  должен находиться в том же каталоге.</p>
<pre class="PROGRAMLISTING"># Этот файл подключается к сценарию.
# Подключаемые файлы могут содержать об"явления переменных, функций и т.п.
# Загружаться может командой 'source' или '.' .

# Инициализация некоторых переменных.

variable1=22
variable2=474
variable3=5
variable4=97

message1="Привет! Как поживаете?"
message2="Досвидания!"

print_message ()
{
# Вывод сообщения переданного в эту функцию.

  if [ -z "$1" ]
  then
    return 1
    # Ошибка, если аргумент отсутствует.
  fi

  echo

  until [ -z "$1" ]
  do
    # Цикл по всем аргументам функции.
    echo -n "$1"
    # Вывод аргумента с подавлением символа перевода строки.
    echo -n " "
    # Вставить пробел, для разделения выводимых аргументов.
    shift
    # Переход к следующему аргументу.
  done  

  echo

  return 0
} 
</pre>
                </div>

                <p>Сценарий может подключить даже самого себя, только
                этому едва ли можно найти какое либо практическое
                применение.</p>

                <div class="EXAMPLE">
                  <a name="SELFSOURCE"></a>

                  <p><strong>Пример 11-19. Пример (бесполезный)
                  сценария, который подключает себя
                  самого.</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# self-source.sh: сценарий, который рекурсивно подключает себя самого."
# Из "Бестолковые трюки", том II.

MAXPASSCNT=100    # Максимальное количество проходов.

echo -n  "$pass_count  "
#  На первом проходе выведет два пробела,
#+ т.к. $pass_count еще не инициализирована.

let "pass_count += 1"
#  Операция инкремента неинициализированной переменной $pass_count
#+ на первом проходе вполне допустима.
#  Этот прием срабатывает в Bash и pdksh, но,
#+ при переносе сценария в другие командные оболочки,
#+ он может оказаться неработоспособным или даже опасным.
#  Лучшим выходом из положения, будет присвоить переменной $pass_count
#+ значение 0, если она неинициализирована.

while [ "$pass_count" -le $MAXPASSCNT ]
do
  . $0   # "Подключение" самого себя.
         # ./$0 (истинная рекурсия) в данной ситуации не сработает.
done  

#  Происходящее здесь фактически не является рекурсией как таковой,
#+ т.к. сценарий как бы "расширяет" себя самого
#+ (добавляя новый блок кода)
#+ на каждом проходе цикла 'while',
#+ командой 'source' в строке 22.
#
#  Само собой разумеется, что первая строка (#!), вновь подключенного сценария,
#+ интерпретируется как комментарий, а не как начало нового сценария (sha-bang)

echo

exit 0   # The net effect is counting from 1 to 100.
         # Very impressive.

# Упражнение:
# ----------
# Напишите сценарий, который использовал бы этот трюк для чего либо полезного.
</pre>
                </div>
              </dd>

              <dt><strong class="COMMAND">exit</strong></dt>

              <dd>
                <p>Безусловное завершение работы сценария. Команде
                <strong class="COMMAND">exit</strong> можно передать целое
                число, которое будет возвращено вызывающему процессу
                как <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXITSTATUSREF">код завершения</a>. Вообще,
                считается хорошей практикой завершать работу сценария,
                за исключением простейших случаев, командой <code class="USERINPUT"><strong>exit 0</strong></code>, чтобы
                проинформировать родительский процесс об успешном
                завершении.</p>

                <div class="NOTE">
                  <table class="NOTE" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                      <td align="left" valign="top">
                        <p>Если сценарий завершается командой <strong class="COMMAND">exit</strong> без аргументов,
                        то в качестве кода завершения сценария
                        принимается код завершения последней
                        выполненной команды, не считая самой команды
                        <strong class="COMMAND">exit</strong>.</p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </dd>

              <dt><a name="EXECREF"></a><strong class="COMMAND">exec</strong></dt>

              <dd>
                <p>Это встроенная команда интерпретатора shell,
                заменяет текущий процесс новым процессом, запускаемым
                командой exec. Обычно, когда командный интерпретатор
                встречает эту команду, то он <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FORKREF">порождает</a> дочерний процесс, чтобы
                исполнить команду. При использовании встроенной команды
                <strong class="COMMAND">exec</strong>, оболочка не порождает
                еще один процесс, а заменяет текущий процесс другим.
                Для сценария это означает его завершение сразу после
                исполнения команды <strong class="COMMAND">exec</strong>. По этой причине, если
                вам встретится <strong class="COMMAND">exec</strong> в сценарии, то, скорее
                всего это будет последняя команда в сценарии.</p>

                <div class="EXAMPLE">
                  <a name="EX54"></a>

                  <p><strong>Пример 11-20. Команда exec</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

exec echo "Завершение \"$0\"."   # Это завершение работы сценария.

# ----------------------------------
# Следующие ниже строки никогда не будут исполнены
echo "Эта строка никогда не будет выведена на экран."

exit 99                       #  Сценарий завершит работу не здесь.
                              #  Проверьте код завершения сценария
                              #+ командой 'echo $?'.
                              #  Он точно не будет равен 99.
</pre>
                </div>

                <div class="EXAMPLE">
                  <a name="SELFEXEC"></a>

                  <p><strong>Пример 11-21. Сценарий, который запускает
                  себя самого</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# self-exec.sh

echo

echo "Эта строка в сценарии единственная, но она продолжает выводиться раз за разом."
echo "PID остался равным $$."
#     Демонстрация того, что команда exec не порождает дочерний процесс.

echo "==================== Для завершения - нажмите Ctl-C ===================="

sleep 1

exec $0   #  Запуск очередного экземпляра этого же сценария
          #+ который замещает предыдущий.

echo "Эта строка никогда не будет выведена!"  # Почему?

exit 0
</pre>
                </div>

                <p>Команда <strong class="COMMAND">exec</strong> так же может
                использоваться для перенаправления. Так, команда <code class="USERINPUT"><strong>exec
                &lt;zzz-file</strong></code> заменит стандартное
                устройство ввода (<code class="FILENAME">stdin</code>) файлом <code class="FILENAME">zzz-file</code> (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REDIR1">Пример 16-1</a>).</p>

                <div class="NOTE">
                  <table class="NOTE" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                      <td align="left" valign="top">
                        <p>Ключ <code class="OPTION">-exec</code> команды <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FINDREF">find</a> -- это не то же
                        самое, что встроенная команда <strong class="COMMAND">exec</strong>.</p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </dd>

              <dt><strong class="COMMAND">shopt</strong></dt>

              <dd>
                <p>Эта команда позволяет изменять ключи (опции)
                оболочки на лету (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AL">Пример 23-1</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#UNAL">Пример 23-2</a>). Ее часто можно
                встретить в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FILESREF1">стартовых файлах</a>, но может
                использоваться и в обычных сценариях. Требует Bash <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BASH2REF">версии 2</a> или выше.</p>
<pre class="PROGRAMLISTING">shopt -s cdspell
# Исправляет незначительные орфографические ошибки в именах каталогов в команде 'cd'

cd /hpme  # Oops! Имелось ввиду '/home'.
pwd       # /home
          # Shell исправил опечатку.
</pre>
                <br>
                <br>
              </dd>
            </dl>
          </div>

          <div class="VARIABLELIST">
            <p><strong><a name="INTCOMMAND1"></a>Команды</strong></p>

            <dl>
              <dt><a name="TRUEREF"></a><strong class="COMMAND">true</strong></dt>

              <dd>
                <p>Команда возвращает код завершения -- <span class="RETURNVALUE">ноль</span>, или успешное
                завершение, и ничего больше.</p>
<pre class="PROGRAMLISTING"># Бесконечный цикл
while true   # вместо ":"
do
   operation-1
   operation-2
   ...
   operation-n
   # Следует предусмотреть способ завершения цикла.
done
</pre>
                <br>
                <br>
              </dd>

              <dt><strong class="COMMAND">false</strong></dt>

              <dd>
                <p>Возвращает <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXITSTATUSREF">код завершения</a>,
                свидетельствующий о неудаче, и ничего более.</p>
<pre class="PROGRAMLISTING"># Цикл, который никогда не будет исполнен
while false
do
   # Следующий код не будет исполнен никогда.
   operation-1
   operation-2
   ...
   operation-n
done  
</pre>
                <br>
                <br>
              </dd>

              <dt><strong class="COMMAND">type [cmd]</strong></dt>

              <dd>
                <p>Очень похожа на внешнюю команду <code>which</code>, <strong class="COMMAND">type cmd</strong> выводит полный путь
                к <span class="QUOTE">"cmd"</span>. В отличие от
                <strong class="COMMAND">which</strong>, <strong class="COMMAND">type</strong> является внутренней
                командой Bash. С опцией <code class="OPTION">-a</code> не только различает ключевые
                слова и внутренние команды, но и определяет
                местоположение внешних команд с именами, идентичными
                внутренним.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>type '['</strong></code>
<code class="COMPUTEROUTPUT">[ is a shell builtin</code>
<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>type -a '['</strong></code>
<code class="COMPUTEROUTPUT">[ is a shell builtin
 [ is /usr/bin/[</code>
             
</pre>
                <br>
                <br>
              </dd>

              <dt><strong class="COMMAND">hash [cmds]</strong></dt>

              <dd>
                <p>Запоминает путь к заданной команде (в хэш-таблице
                командной оболочки), благодаря чему, при повторном
                обращении к ней, оболочка или сценарий уже не будет
                искать путь к команде в <code class="VARNAME">$PATH</code>. При вызове команды <strong class="COMMAND">hash</strong> без аргументов, просто
                выводит содержимое хэш-таблицы. С ключом <code class="OPTION">-r</code> -- очищает хэш-таблицу.</p>
              </dd>

              <dt><strong class="COMMAND">help</strong></dt>

              <dd>
                <p><strong class="COMMAND">help</strong> COMMAND -- выводит
                краткую справку по использованию внутренней команды
                COMMAND. Аналог команды <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WHATISREF">whatis</a>, только для внутренних
                команд.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>help exit</strong></code>
<code class="COMPUTEROUTPUT">exit: exit [n]
    Exit the shell with a status of N.  If N is omitted, the exit status
    is that of the last command executed.</code>
             
</pre>
                <br>
                <br>
              </dd>
            </dl>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="AEN6110"></a>11.1. Команды управления заданиями</h2>

            <p>Некоторые из нижеследующих команд принимают, в качестве
            аргумента, <span class="QUOTE">"идентификатор задания"</span>.
            См. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#JOBIDTABLE">таблицу</a> в конце главы.</p>

            <div class="VARIABLELIST">
              <dl>
                <dt><strong class="COMMAND">jobs</strong></dt>

                <dd>
                  <p>Выводит список заданий, исполняющихся в фоне.
                  Команда <strong class="COMMAND">ps</strong> более информативна.</p>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p><span class="emphasis"><em class="EMPHASIS">Задания</em></span> и <span class="emphasis"><em class="EMPHASIS">процессы</em></span> легко
                          спутать. Некоторые <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BUILTINREF">внутренние команды</a>,
                          такие как <strong class="COMMAND">kill</strong>, <strong class="COMMAND">disown</strong> и <strong class="COMMAND">wait</strong> принимают в
                          качестве параметра либо номер задания, либо
                          номер процесса. Команды <strong class="COMMAND">fg</strong>, <strong class="COMMAND">bg</strong> и <strong class="COMMAND">jobs</strong> принимают
                          только номер задания.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>sleep 100 &amp;</strong></code>
<code class="COMPUTEROUTPUT">[1] 1384</code>

<code class="PROMPT">bash $</code> <code class="USERINPUT"><strong>jobs</strong></code>
<code class="COMPUTEROUTPUT">[1]+  Running                 sleep 100 &amp;</code>
</pre>
                          <br>
                          <br>

                          <p><span class="QUOTE">"1"</span> -- это
                          номер задания (управление заданиями
                          осуществляет текущий командный
                          интерпретатор), а <span class="QUOTE">"1384"</span> --
                          номер процесса (управление процессами
                          осуществляется системой). Завершить
                          задание/процесс ("прихлопнуть")
                          можно либо командой <strong class="COMMAND">kill %1</strong>, либо
                          <strong class="COMMAND">kill 1384</strong>.</p>

                          <p><span class="emphasis"><em class="EMPHASIS">Спасибо
                          S.C.</em></span></p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><strong class="COMMAND">disown</strong></dt>

                <dd>
                  <p>Удаляет задание из таблицы активных заданий
                  командной оболочки.</p>
                </dd>

                <dt><strong class="COMMAND">fg</strong>, <strong class="COMMAND">bg</strong></dt>

                <dd>
                  <p>Команда <strong class="COMMAND">fg</strong> переводит задание из
                  фона на передний план. Команда <strong class="COMMAND">bg</strong> перезапускает
                  приостановленное задание в фоновом режиме. Если эти
                  команды были вызваны без указания номера задания, то
                  они воздействуют на текущее исполняющееся
                  задание.</p>
                </dd>

                <dt><a name="WAITREF"></a><strong class="COMMAND">wait</strong></dt>

                <dd>
                  <p>Останавливает работу сценария до тех пор пока не
                  будут завершены все фоновые задания или пока не будет
                  завершено задание/процесс с указанным номером
                  задания/PID процесса. Возвращает <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXITSTATUSREF">код завершения</a> указанного
                  задания/процесса.</p>

                  <p>Вы можете использовать команду <strong class="COMMAND">wait</strong> для предотвращения
                  преждевременного завершения сценария до того, как
                  завершит работу фоновое задание.</p>

                  <div class="EXAMPLE">
                    <a name="EX39"></a>

                    <p><strong>Пример 11-22. Ожидание завершения
                    процесса перед тем как продолжить
                    работу</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

ROOT_UID=0   # Только пользователь с $UID = 0 имеет привилегии root.
E_NOTROOT=65
E_NOPARAMS=66

if [ "$UID" -ne "$ROOT_UID" ]
then
  echo "Для запуска этого сценария вы должны обладать привилегиями root."
  exit $E_NOTROOT
fi

if [ -z "$1" ]
then
  echo "Порядок использования: `basename $0` имя-файла"
  exit $E_NOPARAMS
fi


echo "Обновляется база данных 'locate'..."
echo "Это может занять продолжительное время."
updatedb /usr &amp;     # Должна запускаться с правами root.

wait
# В этом месте сценарий приостанавливает свою работу до тех пор, пока не отработает 'updatedb'.
# Желательно обновить базу данных перед тем как выполнить поиск файла.

locate $1

# В худшем случае, без команды wait, сценарий завершил бы свою работу до того,
# как завершила бы работу утилита 'updatedb',
# сделав из нее "осиротевший" процесс.

exit 0
</pre>
                  </div>

                  <p>Команда <strong class="COMMAND">wait</strong> может принимать
                  необязательный параметр -- номер задания/процесса,
                  например, <strong class="COMMAND">wait %1</strong> или <strong class="COMMAND">wait $PPID</strong>. См. таблицу <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#JOBIDTABLE">идентификации заданий</a>.</p>

                  <p><a name="WAITHANG"></a></p>

                  <div class="TIP">
                    <table class="TIP" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/tip.gif" hspace="5" alt="Tip"></td>

                        <td align="left" valign="top">
                          <p>При запуске команды в фоне из сценария
                          может возникнуть ситуация, когда сценарий
                          приостанавливает свою работу до тех пор, пока
                          не будет нажата клавиша <strong class="KEYCAP">ENTER</strong>. Это, кажется,
                          происходит с командами, делающими вывод на
                          <code class="FILENAME">stdout</code>. Такое
                          поведение может вызывать раздражение у
                          пользователя.</p>
<pre class="PROGRAMLISTING">#!/bin/bash
# test.sh

ls -l &amp;
echo "Done."
</pre>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>./test.sh</strong></code>
<code class="COMPUTEROUTPUT">Done.
 [bozo@localhost test-scripts]$ total 1
 -rwxr-xr-x    1 bozo     bozo           34 Oct 11 15:09 test.sh
 _</code>
              
</pre>
                          <br>
                          <br>

                          <p>Разместив команду <strong class="COMMAND">wait</strong>, после запуска
                          фонового задания, можно предотвратить такое
                          поведение сценария.</p>
<pre class="PROGRAMLISTING">#!/bin/bash
# test.sh

ls -l &amp;
echo "Done."
wait
</pre>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>./test.sh</strong></code>
<code class="COMPUTEROUTPUT">Done.
 [bozo@localhost test-scripts]$ total 1
 -rwxr-xr-x    1 bozo     bozo           34 Oct 11 15:09 test.sh</code>
              
</pre>
                          <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IOREDIRREF">Перенаправление</a>
                          вывода в файл или даже на устройство <code class="FILENAME">/dev/null</code> также
                          снимает эту проблему. <br>
                          <br>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><strong class="COMMAND">suspend</strong></dt>

                <dd>
                  <p>Действует аналогично нажатию на комбинацию клавиш
                  <strong class="KEYCAP">Control+</strong>-<strong class="KEYCAP">Z</strong>, за исключением того, что
                  она приостанавливает работу командной оболочки.</p>
                </dd>

                <dt><strong class="COMMAND">logout</strong></dt>

                <dd>
                  <p>Завершает сеанс работы командной оболочки, можно
                  указать необязательный <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXITSTATUSREF">код завершения</a>.</p>
                </dd>

                <dt><a name="TIMESREF"></a><strong class="COMMAND">times</strong></dt>

                <dd>
                  <p>Выдает статистику исполнения команд в единицах
                  системного времени, в следующем виде:</p>
<pre class="SCREEN"><code class="COMPUTEROUTPUT">0m0.020s 0m0.020s</code>
</pre>
                  Имеет весьма ограниченную сферу применения, так как
                  сценарии крайне редко подвергаются
                  профилированию.<br>
                  <br>
                </dd>

                <dt><a name="KILLREF"></a><strong class="COMMAND">kill</strong></dt>

                <dd>
                  <p>Принудительное завершение процесса путем передачи
                  ему соответствующего сигнала (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#KILLPROCESS">Пример 13-4</a>).</p>

                  <div class="EXAMPLE">
                    <a name="SELFDESTRUCT"></a>

                    <p><strong>Пример 11-23. Сценарий, завершающий себя
                    сам с помощью команды kill</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# self-destruct.sh

kill $$  # Сценарий завершает себя сам.
         # Надеюсь вы еще не забыли, что "$$" -- это PID сценария.

echo "Эта строка никогда не будет выведена."
# Вместо него на stdout будет выведено сообщение "Terminated".

exit 0

#  Какой код завершения вернет сценарий?
#
# sh self-destruct.sh
# echo $?
# 143
#
# 143 = 128 + 15
#             сигнал TERM
</pre>
                  </div>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p>Команда <code class="USERINPUT"><strong>kill
                          -l</strong></code> выведет список всех <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SIGNALD">сигналов</a>. Команда <code class="USERINPUT"><strong>kill
                          -9</strong></code> -- это <span class="QUOTE">"жесткий
                          kill"</span>, она используется, как
                          правило, для завершения зависших процессов,
                          которые упорно отказываются
                          "умирать", отвергая простой <strong class="COMMAND">kill</strong>. Иногда
                          достаточно подать команду <code class="USERINPUT"><strong>kill
                          -15</strong></code>. <span class="QUOTE">"Процессы-зомби"</span>,
                          т.е. процессы, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FORKREF">"родители"</a>
                          которых уже завершили работу, не могут быть
                          "убиты" таким способом (невозможно
                          "убить" "мертвого"), рано
                          или поздно с ними "расправится"
                          процесс <strong class="COMMAND">init</strong>.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><strong class="COMMAND">command</strong></dt>

                <dd>
                  <p>Директива <strong class="COMMAND">command COMMAND</strong> запрещает
                  использование псевдонимов и функций с именем <span class="QUOTE">"COMMAND"</span>.</p>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p>Это одна из трех директив командного
                          интерпретатора, которая влияет на обработку
                          команд. Другие две -- <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BLTREF">builtin</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ENABLEREF">enable</a>.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><a name="BLTREF"></a><strong class="COMMAND">builtin</strong></dt>

                <dd>
                  <p>Конструкция <strong class="COMMAND">builtin BUILTIN_COMMAND</strong>
                  запускает <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BUILTINREF">внутреннюю команду</a> <span class="QUOTE">"BUILTIN_COMMAND"</span>, на
                  время запрещая использование функций и внешних
                  системных команд с тем же именем.</p>
                </dd>

                <dt><a name="ENABLEREF"></a><strong class="COMMAND">enable</strong></dt>

                <dd>
                  <p>Либо запрещает, либо разрешает вызов внутренних
                  команд. Например, <strong class="COMMAND">enable -n kill</strong> запрещает
                  использование внутренней команды <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#KILLREF">kill</a>, в результате, когда
                  интерпретатор встретит команду <strong class="COMMAND">kill</strong>, то он вызовет внешнюю
                  команду <strong class="COMMAND">kill</strong>, т.е. <code class="FILENAME">/bin/kill</code>.</p>

                  <p><a name="ENABLEREF1"></a>Команда <code class="OPTION">enable -a</code> выведет список всех
                  внутренних команд, указывая для каждой --
                  действительно ли она разрешена. Команда <code class="OPTION">enable -f filename</code> загрузит <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BUILTINREF">внутренние команды</a> как
                  разделяемую библиотеку (DLL) из указанного объектного
                  файла. <a name="AEN6343" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN6343"><span class="footnote">[26]</span></a>.</p>
                </dd>

                <dt><strong class="COMMAND">autoload</strong></dt>

                <dd>
                  <p>Перенесена в Bash из <span class="emphasis"><em class="EMPHASIS">ksh</em></span>. Если функция
                  объявлена как <strong class="COMMAND">autoload</strong>, то она будет
                  загружена из внешнего файла в момент первого вызова.
                  <a name="AEN6361" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN6361"><span class="footnote">[27]</span></a> Такой прием
                  помогает экономить системные ресурсы.</p>

                  <p>Обратите внимание: <strong class="COMMAND">autoload</strong> не является частью
                  ядра Bash. Ее необходимо загрузить с помощью команды
                  <strong class="COMMAND">enable -f</strong> (см. выше).</p>
                </dd>
              </dl>
            </div>

            <div class="TABLE">
              <a name="JOBIDTABLE"></a>

              <p><strong>Таблица 11-1. Идентификация
              заданий</strong></p>

              <table border="1" class="CALSTABLE">
                <thead>
                  <tr>
                    <th align="left" valign="top">Нотация</th>

                    <th align="left" valign="top">Описание</th>
                  </tr>
                </thead>

                <tbody>
                  <tr>
                    <td align="left" valign="top"><code class="OPTION">%N</code></td>

                    <td align="left" valign="top">Номер задания [N]</td>
                  </tr>

                  <tr>
                    <td align="left" valign="top"><code class="OPTION">%S</code></td>

                    <td align="left" valign="top">Вызов (командная строка) задания,
                    которая начинается со строки <span class="emphasis"><em class="EMPHASIS">S</em></span></td>
                  </tr>

                  <tr>
                    <td align="left" valign="top"><code class="OPTION">%?S</code></td>

                    <td align="left" valign="top">Вызов (командная строка) задания,
                    которая содержит строку <span class="emphasis"><em class="EMPHASIS">S</em></span></td>
                  </tr>

                  <tr>
                    <td align="left" valign="top"><code class="OPTION">%%</code></td>

                    <td align="left" valign="top"><span class="QUOTE">"текущее"</span> задание
                    (последнее задание приостановленное на переднем
                    плане или запущенное в фоне)</td>
                  </tr>

                  <tr>
                    <td align="left" valign="top"><code class="OPTION">%+</code></td>

                    <td align="left" valign="top"><span class="QUOTE">"текущее"</span> задание
                    (последнее задание приостановленное на переднем
                    плане или запущенное в фоне)</td>
                  </tr>

                  <tr>
                    <td align="left" valign="top"><code class="OPTION">%-</code></td>

                    <td align="left" valign="top">Последнее задание</td>
                  </tr>

                  <tr>
                    <td align="left" valign="top"><code class="OPTION">$!</code></td>

                    <td align="left" valign="top">Последний фоновый процесс</td>
                  </tr>
                </tbody>
              </table>
            </div>
          </div>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="EXTERNAL"></a>Глава 12. Внешние команды, программы и
          утилиты</h1>

          <p>Благодаря стандартизации набора команд UNIX-систем,
          сценарии, на языке командной оболочки, могут быть легко
          перенесены из системы в систему практически без изменений.
          Мощь сценариев складывется из наборв системных команд и
          директив командной оболочки с простыми программными
          конструкциями.</p>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="BASIC"></a>12.1. Базовые команды</h2>

            <div class="VARIABLELIST">
              <p><strong><a name="BASICCOMMANDS1"></a>Первая команда, с которой
              сталкиваются новички</strong></p>

              <dl>
                <dt><a name="LSREF"></a><strong class="COMMAND">ls</strong></dt>

                <dd>
                  <p>Команда вывода <span class="QUOTE">"списка"</span> файлов.
                  Многие недооценивают всю мощь этой скромной команды.
                  Например, с ключом <code class="OPTION">-R</code>, рекурсивный обход дерева
                  каталогов, командв <strong class="COMMAND">ls</strong> выводит содержимое
                  каталогов в виде древовидной структуры. Вот еще ряд
                  любопытных ключей (опций) команды <strong class="COMMAND">ls</strong>: <code class="OPTION">-S</code> -- сортировка по размеру
                  файлов, <code class="OPTION">-t</code> -- сортировка по времени
                  последней модификации файла и <code class="OPTION">-i</code> -- выводит список файлов с их
                  inode (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IDELETE">Пример 12-3</a>).</p>

                  <div class="EXAMPLE">
                    <a name="EX40"></a>

                    <p><strong>Пример 12-1. Создание оглавления диска
                    для записи <span class="ABBREV">CDR</span>, с помощью команды
                    ls</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# burn-cd.sh
# Сценарий, автоматизирующий процесс прожигания CDR.


SPEED=2          # Если ваше "железо" поддерживает более высокую скорость записи -- можете увеличить этот параметр
IMAGEFILE=cdimage.iso
CONTENTSFILE=contents
DEFAULTDIR=/opt  # В этом каталоге находятся файлы, которые будут записаны на CD.
                 # Каталог должен существовать.

# Используется пакет "cdrecord" от Joerg Schilling.
# (http://www.fokus.gmd.de/nthp/employees/schilling/cdrecord.html)

#  Если этот сценарий предполагается запускать с правами обычного пользователя,
#+ то необходимо установить флаг suid на cdrecord
#+ (chmod u+s /usr/bin/cdrecord, эта команда должна быть выполнена root-ом).

if [ -z "$1" ]
then
  IMAGE_DIRECTORY=$DEFAULTDIR
  # Каталог по-умолчанию, если иной каталог не задан из командной строки.
else
    IMAGE_DIRECTORY=$1
fi

# Создать файл "table of contents".
ls -lRF $IMAGE_DIRECTORY &gt; $IMAGE_DIRECTORY/$CONTENTSFILE
# Ключ "l" -- "расширенный" формат вывода списка файлов.
# Ключ "R" -- рекурсивный обход дерева каталогов.
# Ключ "F" -- добавляет дополнительные метки к именам файлов (к именам каталогов добавдяет оконечный символ /).
echo "Создано оглавление."

# Создать iso-образ.
mkisofs -r -o $IMAGFILE $IMAGE_DIRECTORY
echo "Создан iso-образ файловой системы ISO9660 ($IMAGEFILE)."

# "Прожигание" CDR.
cdrecord -v -isosize speed=$SPEED dev=0,0 $IMAGEFILE
echo "Запись диска."
echo "Наберитесь терпения, это может потребовать некоторого времени."

exit 0
</pre>
                  </div>
                </dd>

                <dt><a name="CATREF"></a><strong class="COMMAND">cat</strong>, <strong class="COMMAND">tac</strong></dt>

                <dd>
                  <p><strong class="COMMAND">cat</strong> -- это акроним от <em class="WORDASWORD">concatenate</em>, выводит
                  содержимое списка файлов на <code class="FILENAME">stdout</code>. Для объединения файлов
                  в один файл может использоваться в комбинации с
                  операциями перенаправления (<span class="TOKEN">&gt;</span> или <span class="TOKEN">&gt;&gt;</span>).</p>
<pre class="PROGRAMLISTING">cat filename cat file.1 file.2 file.3 &gt; file.123
</pre>
                  Ключ <code class="OPTION">-n</code>, команды <strong class="COMMAND">cat</strong>, вставляет порядковые
                  номера строк в выходном файле. Ключ <code class="OPTION">-b</code> -- нумерут только не пустые
                  строки. Ключ <code class="OPTION">-v</code> выводит непечатаемые символы
                  в нотации с символом <span class="TOKEN">^</span>. Ключ <code class="OPTION">-s</code> заменяет несколько пустых
                  строк, идущих подряд, одной пустой строкой.<br>
                  <br>

                  <p>см. также <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LNUM">Пример 12-21</a> and <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ROT13">Пример 12-17</a>.</p>

                  <p><strong class="COMMAND">tac</strong> -- выводит содержимое
                  файлов в обратном порядке, от последней строки к
                  первой.</p>
                </dd>

                <dt><strong class="COMMAND">rev</strong></dt>

                <dd>
                  <p>выводит все строки файла задом наперед на <code class="FILENAME">stdout</code>. Это не то же самое,
                  что <strong class="COMMAND">tac</strong>. Команда <strong class="COMMAND">rev</strong> сохраняет порядок
                  следования строк, но переворачивает каждую строку
                  задом наперед.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>cat file1.txt</strong></code>
<code class="COMPUTEROUTPUT">Это строка 1.
 Это строка 2.</code>


<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>tac file1.txt</strong></code>
<code class="COMPUTEROUTPUT">Это строка 2.
 Это строка 1.</code>


<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>rev file1.txt</strong></code>
<code class="COMPUTEROUTPUT">.1 акортс отЭ
 .2 акортс отЭ</code>
             
</pre>
                  <br>
                  <br>
                </dd>

                <dt><strong class="COMMAND">cp</strong></dt>

                <dd>
                  <p>Команда копирования файлов. <code class="USERINPUT"><strong>cp file1
                  file2</strong></code> скопирует <code class="FILENAME">file1</code> в <code class="FILENAME">file2</code>, перезаписав <code class="FILENAME">file2</code> если он уже существовал
                  (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX42">Пример 12-5</a>).</p>

                  <div class="TIP">
                    <table class="TIP" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/tip.gif" hspace="5" alt="Tip"></td>

                        <td align="left" valign="top">
                          <p>С флагами <code class="OPTION">-a</code> и <code class="OPTION">-r</code>, или <code class="OPTION">-R</code> выполняет копирование
                          дерева каталогов.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><strong class="COMMAND">mv</strong></dt>

                <dd>
                  <p>Команда <span class="emphasis"><em class="EMPHASIS">перемещения</em></span> файла.
                  Эквивалентна комбинации команд <strong class="COMMAND">cp</strong> и <strong class="COMMAND">rm</strong>. Может использоваться
                  для перемещения большого количества файлов или для
                  переименования каталогов. Примеры использования
                  команды <strong class="COMMAND">mv</strong> вы найдете в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RFE">Пример 9-17</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RN">Пример A-3</a>.</p>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p>При использовании в неинтерактивных
                          сценариях, команде <strong class="COMMAND">mv</strong> следует
                          передавать ключ <code class="OPTION">-f</code>, чтобы подавить
                          запрос подтверждения на перемещение.</p>

                          <p>Если в качестве каталога назначения указан
                          существующий каталог, то перемещаемый каталог
                          становится подкаталогом каталога
                          назначения..</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>mv source_directory target_directory</strong></code>

<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>ls -lF target_directory</strong></code>
<code class="COMPUTEROUTPUT">total 1
 drwxrwxr-x    2 bozo  bozo      1024 May 28 19:20 source_directory/</code>
             
</pre>
                          <br>
                          <br>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><strong class="COMMAND">rm</strong></dt>

                <dd>
                  <p>Удаляет (remove) файл(ы). Ключ <code class="OPTION">-f</code> позволяет удалять даже файлы
                  ТОЛЬКО-ДЛЯ-ЧТЕНИЯ и подавляет запрос подтверждения на
                  удаление.</p>

                  <div class="WARNING">
                    <table class="WARNING" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/warning.gif" hspace="5" alt="Warning"></td>

                        <td align="left" valign="top">
                          <p>С ключом <code class="OPTION">-r</code>, удаляет все файлы в
                          подкаталогах.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><strong class="COMMAND">rmdir</strong></dt>

                <dd>
                  <p>Удаляет каталог. Удаляемый каталог не должен
                  содержать файлов, включая <a name="DOTFILESREF"></a> <span class="QUOTE">"скрытые файлы"</span>, <a name="AEN6567" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN6567"><span class="footnote">[28]</span></a> иначе каталог не
                  будет удален.</p>
                </dd>

                <dt><strong class="COMMAND">mkdir</strong></dt>

                <dd>
                  <p>Создает новый каталог. <code class="USERINPUT"><strong>mkdir -p
                  project/programs/December</strong></code> создает
                  каталог с заданным именем в требуемом каталоге. Ключ
                  <code class="REPLACEABLE"><em>-p</em></code> позволяет
                  создавать промежуточные родительские каталоги.</p>
                </dd>

                <dt><a name="CHMODREF"></a><strong class="COMMAND">chmod</strong></dt>

                <dd>
                  <p>Изменяет атрибуты существующего файла (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX44">Пример 11-10</a>).</p>
<pre class="PROGRAMLISTING">chmod +x filename
# Делает файл "filename" доступным для исполнения всем пользователям.

chmod u+s filename
# Устанавливается бит "suid" для "filename".
# В результате, любой пользователь сможет запустить "filename" с привилегиями владельца файла.
# (Это не относится к файлам-сценариям на языке командной оболочки.)
</pre>
                  <br>
                  <br>
<pre class="PROGRAMLISTING">chmod 644 filename
# Выдает право на запись/чтение владельцу файла "filename", и право на чтение
# всем остальным
# (восьмеричное число).
</pre>
                  <br>
                  <br>
<pre class="PROGRAMLISTING">chmod 1777 directory-name
# Выдает право на чтение, запись и исполнение файлов в каталоге,
# дополнительно устанавливает "sticky bit".
# Это означает, что удалять файлы в этом каталоге могут только владельцы файлов,
# владелец каталога и, само собой разумеется, root.
</pre>
                  <br>
                  <br>
                </dd>

                <dt><strong class="COMMAND">chattr</strong></dt>

                <dd>
                  <p>Изменяет атрибуты файла. Эта команда подобна
                  команде <strong class="COMMAND">chmod</strong>, за исключением
                  синтаксиса вызова, и работает исключительно в
                  файловой системе <span class="emphasis"><em class="EMPHASIS">ext2</em></span>.</p>
                </dd>

                <dt><strong class="COMMAND">ln</strong></dt>

                <dd>
                  <p>Создает ссылку на существующий файл. Чаще всего
                  используется с ключом <code class="OPTION">-s</code>, что означает символическую,
                  или <span class="QUOTE">"мягкую"</span> (symbolic
                  или <span class="QUOTE">"soft"</span>) ссылку.
                  Позволяет задавать несколько имен одному и тому же
                  файлу и превосходная альтернатива
                  "псевдонимам" (алиасам) (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX18">Пример 4-6</a>).</p>

                  <p><code class="USERINPUT"><strong>ln -s oldfile
                  newfile</strong></code> создает ссылку, с именем <code class="FILENAME">newfile</code>, на существующий файл
                  <code class="FILENAME">oldfile</code>, .</p>
                </dd>

                <dt><strong class="COMMAND">man</strong>, <strong class="COMMAND">info</strong></dt>

                <dd>
                  <p>Команды доступа к справочным и информационным
                  страницам по системным командам и установленным
                  программам и утилитам. Как правило, страницы <span class="emphasis"><em class="EMPHASIS">info</em></span> содержат более
                  подробную информацию, чем <span class="emphasis"><em class="EMPHASIS">man</em></span>.</p>
                </dd>
              </dl>
            </div>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="MOREADV"></a>12.2. Более сложные команды</h2>

            <div class="VARIABLELIST">
              <p><strong><a name="CCLISTING1"></a>Команды для более опытных
              пользователей</strong></p>

              <dl>
                <dt><a name="FINDREF"></a><strong class="COMMAND">find</strong></dt>

                <dd>
                  <p>-exec <code class="REPLACEABLE"><em>COMMAND</em></code> \;</p>

                  <p>Для каждого найденного файла, соответствующего
                  заданному шаблону поиска, выполняет команду <code class="REPLACEABLE"><em>COMMAND</em></code>. Командная
                  строка должна завершаться последовательностью
                  символов <span class="TOKEN">\;</span> (здесь символ <span class="QUOTE">";"</span> экранирован
                  обратным слэшем, чтобы информировать командную
                  оболочку о том, что символ <span class="QUOTE">";"</span> должен быть
                  передан команде <strong class="COMMAND">find</strong> как обычный символ).
                  Если <code class="REPLACEABLE"><em>COMMAND</em></code> содержит
                  <span class="TOKEN">{}</span>, то <strong class="COMMAND">find</strong> подставляет полное имя
                  найденного файла вместо <span class="QUOTE">"{}"</span>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>find ~/ -name '*.txt'</strong></code>
<code class="COMPUTEROUTPUT">/home/bozo/.kde/share/apps/karm/karmdata.txt
/home/bozo/misc/irmeyc.txt
/home/bozo/test-scripts/1.txt</code>
             
</pre>
                  <br>
                  <br>
<pre class="PROGRAMLISTING">find /home/bozo/projects -mtime 1
#  Найти все файлы в каталоге /home/bozo/projects и вложенных подкаталогах,
#+ которые изменялись в течение последних суток.
#
#  mtime = время последнего изменения файла
#  ctime = время последнего изменения атрибутов файла (через 'chmod' или как-то иначе)
#  atime = время последнего обращения к файлу

DIR=/home/bozo/junk_files
find "$DIR" -type f -atime +5 -exec rm {} \;
#  Удалить все файлы в каталоге "/home/bozo/junk_files"
#+ к которым не было обращений в течение последних 5 дней.
#
#  "-type filetype", где
#  f = обычный файл
#  d = каталог, и т.п.
#  (Полный список ключей вы найдете в 'man find'.)
</pre>
                  <br>
                  <br>
<pre class="PROGRAMLISTING">find /etc -exec grep '[0-9][0-9]*[.][0-9][0-9]*[.][0-9][0-9]*[.][0-9][0-9]*' {} \;

# Поиск всех IP-адресов (xxx.xxx.xxx.xxx) в файлах каталога  /etc.
# Однако эта команда выводит не только IP-адреса, как этого избежать?

# Примерно так:

find /etc -type f -exec cat '{}' \; | tr -c '.[:digit:]' '\n' \
 | grep '^[^.][^.]*\.[^.][^.]*\.[^.][^.]*\.[^.][^.]*$'
# [:digit:] -- один из символьных классов
# введен в стандарт POSIX 1003.2.

# Спасибо S.C.
</pre>
                  <br>
                  <br>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p>Не следует путать опцию <code class="OPTION">-exec</code> команды <strong class="COMMAND">find</strong> с внутренней
                          командой Bash -- <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXECREF">exec</a>.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>

                  <div class="EXAMPLE">
                    <a name="EX57"></a>

                    <p><strong>Пример 12-2. Badname, удаление файлов в
                    текущем каталоге, имена которых содержат
                    недопустимые символы и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WHITESPACEREF">пробелы</a>.</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# Удаление файлов в текущем каталоге, чьи имена содержат недопустимые символы.

for filename in *
do
badname=`echo "$filename" | sed -n /[\+\{\;\"\\\=\?~\(\)\&lt;\&gt;\&amp;\*\|\$]/p`
# Недопустимые символы в именах файлов:     + { ; " \ = ? ~ ( ) &lt; &gt; &amp; * | $
rm $badname 2&gt;/dev/null    # Сообщения об ошибках "выстреливаются" в никуда.
done

# Теперь "позаботимся" о файлах, чьи имена содержат пробельные символы.
find . -name "* *" -exec rm -f {} \;
# На место "{}", find подставит полное имя файла.
# Символ '\' указывает на то, что ';' интерпретируется как обычный символ, а не как конец команды.

exit 0

#---------------------------------------------------------------------
# Строки, приведенные ниже, не будут выполнены, т.к. выше стоит команда "exit".

# Альтернативный вариант сценария:
find . -name '*[+{;"\\=?~()&lt;&gt;&amp;*|$ ]*' -exec rm -f '{}' \;
exit 0
# (Спасибо S.C.)
</pre>
                  </div>

                  <div class="EXAMPLE">
                    <a name="IDELETE"></a>

                    <p><strong>Пример 12-3. Удаление файла по его
                    номеру <span class="emphasis"><em class="EMPHASIS">inode</em></span></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# idelete.sh: Удаление файла по номеру inode.

#  Этот прием используется в тех случаях, когда имя файла начинается с недопустимого символа,
#+ например, ? или -.

ARGCOUNT=1                      # Имя файла должно быть передано в сценарий.
E_WRONGARGS=70
E_FILE_NOT_EXIST=71
E_CHANGED_MIND=72

if [ $# -ne "$ARGCOUNT" ]
then
  echo "Порядок использования: `basename $0` filename"
  exit $E_WRONGARGS
fi

if [ ! -e "$1" ]
then
  echo "Файл \""$1"\" не найден."
  exit $E_FILE_NOT_EXIST
fi

inum=`ls -i | grep "$1" | awk '{print $1}'`
# inum = номер inode (index node) файла
# Каждый файл имеет свой inode, где хранится информация о физическом расположении файла.

echo; echo -n "Вы совершенно уверены в том, что желаете удалить \"$1\" (y/n)? "
# Ключ '-v' в команде 'rm' тоже заставит команду вывести подобный запрос.
read answer
case "$answer" in
[nN]) echo "Передумали?"
      exit $E_CHANGED_MIND
      ;;
*)    echo "Удаление файла \"$1\".";;
esac

find . -inum $inum -exec rm {} \;
echo "Файл "\"$1"\" удален!"

exit 0
</pre>
                  </div>

                  <p>Дополнительные примеры по использованию команды
                  <strong class="COMMAND">find</strong> вы найдете в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX48">Пример 12-22</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX58">Пример 3-4</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FINDSTRING">Пример 10-9</a>. В страницах
                  справочного ркуоводства (man find) вы найдете более
                  подробную информацию об этой достаточно сложной и
                  мощной команде.</p>
                </dd>

                <dt><strong class="COMMAND">xargs</strong></dt>

                <dd>
                  <p>Команда передачи аргументов указанной команде. Она
                  разбивает поток аргументов на отдельные составляющие
                  и поочередно передает их заданной команде для
                  обработки. Эта команда может рассматриваться как
                  мощная замена обратным одиничным кавычкам. Зачастую,
                  когда команды, заключенные в обратные одиночные
                  кавычки, завершаются с ошибкой <span class="ERRORNAME">too many arguments</span> (слишком
                  много аргументов), использование <strong class="COMMAND">xargs</strong> позволяет обойти это
                  ограничение. Обычно, <strong class="COMMAND">xargs</strong> считывает список
                  аргументов со стандартного устройства ввода <code class="FILENAME">stdin</code> или из канала
                  (конвейера), но может считывать информацию и из
                  файла.</p>

                  <p>Если команда не задана, то по-умолчанию
                  выполняется <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ECHOREF">echo</a>. При передаче аргументов по
                  конвейеру, <strong class="COMMAND">xargs</strong> допускает наличие
                  пробельных символов и символов перевода строки,
                  которые затем автоматически отбрасываются.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>ls -l</strong></code>
<code class="COMPUTEROUTPUT">total 0
-rw-rw-r--    1 bozo  bozo         0 Jan 29 23:58 file1
-rw-rw-r--    1 bozo  bozo         0 Jan 29 23:58 file2</code>


<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>ls -l | xargs</strong></code>
<code class="COMPUTEROUTPUT">total 0 -rw-rw-r-- 1 bozo bozo 0 Jan 29 23:58 file1 -rw-rw-r-- 1 bozo bozo 0 Jan 29 23:58 file2</code>
             
</pre>
                  <br>
                  <br>

                  <p><code class="USERINPUT"><strong>ls | xargs -p -l
                  gzip</strong></code> -- упакует с помощью <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GZIPREF">gzip</a> все файлы в текущем
                  каталоге, выводя запрос на подтверждение для каждого
                  файла.</p>

                  <div class="TIP">
                    <table class="TIP" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/tip.gif" hspace="5" alt="Tip"></td>

                        <td align="left" valign="top">
                          <p><strong class="COMMAND">xargs</strong> имеет очень
                          любопытный ключ <code class="OPTION">-n <code class="REPLACEABLE"><em>NN</em></code></code>,
                          который ограничивает количество передаваемых
                          аргументов за один "присест" числом
                          <code class="REPLACEABLE"><em>NN</em></code>.</p>

                          <p><code class="USERINPUT"><strong>ls | xargs -n 8
                          echo</strong></code> -- выведет список файлов
                          текущего каталога в <code class="LITERAL">8</code> колонок.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>

                  <div class="TIP">
                    <table class="TIP" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/tip.gif" hspace="5" alt="Tip"></td>

                        <td align="left" valign="top">
                          <p>Еще одна полезная опция -- <code class="OPTION">-0</code>, в комбинации с
                          <strong class="COMMAND">find -print0</strong> или
                          <strong class="COMMAND">grep -lZ</strong> позволяет
                          обрабатывать аргументы, содержащие пробелы и
                          кавычки.</p>

                          <p><code class="USERINPUT"><strong>find / -type f
                          -print0 | xargs -0 grep -liwZ GUI | xargs -0
                          rm -f</strong></code></p>

                          <p><code class="USERINPUT"><strong>grep -rliwZ GUI /
                          | xargs -0 rm -f</strong></code></p>

                          <p>Обе вышеприведенные команды удалят все
                          файлы, содержащие в своем имени комбинацию
                          символов <span class="QUOTE">"GUI"</span>. <span class="emphasis"><em class="EMPHASIS">(Спасибо
                          S.C.)</em></span></p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>

                  <div class="EXAMPLE">
                    <a name="EX41"></a>

                    <p><strong>Пример 12-4. Использование команды xargs
                    для мониторинга системного журнала</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# Создание временного файла мониторинга в текщем каталоге,
# куда переписываются несколько последних строк из /var/log/messages.

# Обратите внимание: если сценарий запускается обычным пользователем,
# то файл /var/log/messages должен быть доступен на чтение этому пользователю.
#         #root chmod 644 /var/log/messages

LINES=5

( date; uname -a ) &gt;&gt;logfile
# Время и информация о системе
echo --------------------------------------------------------------------- &gt;&gt;logfile
tail -$LINES /var/log/messages | xargs |  fmt -s &gt;&gt;logfile
echo &gt;&gt;logfile
echo &gt;&gt;logfile

exit 0

# Упражнение:
# --------
#  Измените сценарий таким образом, чтобы он мог отслеживать изменения в /var/log/messages
#+ с интервалом в 20 минут.
#  Подсказка: воспользуйтесь командой "watch".
</pre>
                  </div>

                  <div class="EXAMPLE">
                    <a name="EX42"></a>

                    <p><strong>Пример 12-5. copydir, копирование файлов
                    из текущего каталога в другое место, с помощью
                    xargs</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# Копирует все файлы из текущего каталога
# в каталог, указанный в командной строке.

if [ -z "$1" ]   # Выход, если каталог назначения не задан.
then
  echo "Порядок использования: `basename $0` directory-to-copy-to"
  exit 65
fi

ls . | xargs -i -t cp ./{} $1
# Этот сценария является точным эквивалентом
#    cp * $1
# если в именах файлов не содержатся пробельные символы.

exit 0
</pre>
                  </div>
                </dd>

                <dt><a name="EXPRREF"></a><code class="USERINPUT"><strong>expr</strong></code></dt>

                <dd>
                  <p>Универсальный обработчик выражений: вычисляет
                  заданное выражение (аргументы должны отделяться
                  пробелами). Выражения могут быть арифметическими,
                  логическими или строковыми.</p>

                  <div class="VARIABLELIST">
                    <dl>
                      <dt><code class="USERINPUT"><strong>expr 3 +
                      5</strong></code></dt>

                      <dd>
                        <p>возвратит <code class="LITERAL">8</code></p>
                      </dd>

                      <dt><code class="USERINPUT"><strong>expr 5 %
                      3</strong></code></dt>

                      <dd>
                        <p>возвратит 2</p>
                      </dd>

                      <dt><code class="USERINPUT"><strong>expr 5 \*
                      3</strong></code></dt>

                      <dd>
                        <p>возвратит 15</p>

                        <p>В арифметических выражениях, оператор
                        умножения обязательно должен экранироваться
                        обратным слэшем.</p>
                      </dd>

                      <dt><code class="USERINPUT"><strong>y=`expr $y +
                      1`</strong></code></dt>

                      <dd>
                        <p>Операция инкремента переменной, то же самое,
                        что и <code class="USERINPUT"><strong>let
                        y=y+1</strong></code>, или <code class="USERINPUT"><strong>y=$(($y+1))</strong></code>.
                        Пример <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ARITHEXPREF">подстановки арифметических
                        выражений</a>.</p>
                      </dd>

                      <dt><a name="EXPEXTRSUB"></a><code class="USERINPUT"><strong>z=`expr substr $string
                      $position $length`</strong></code></dt>

                      <dd>
                        <p>Извлекает подстроку длиной $length символов,
                        начиная с позиции $position.</p>
                      </dd>
                    </dl>
                  </div>

                  <div class="EXAMPLE">
                    <a name="EX45"></a>

                    <p><strong>Пример 12-6. Пример работы с
                    expr</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# Демонстрация некоторых приемов работы с командой 'expr'
# =======================================

echo

# Арифметические операции
# -------------- --------

echo "Арифметические операции"
echo
a=`expr 5 + 3`
echo "5 + 3 = $a"

a=`expr $a + 1`
echo
echo "a + 1 = $a"
echo "(инкремент переменной)"

a=`expr 5 % 3`
# остаток от деления (деление по модулю)
echo
echo "5 mod 3 = $a"

echo
echo

# Логические операции
# ---------- --------

#  Возвращает 1 если выражение истинноо, 0 -- если ложно,
#+ в противоположность соглашениям, принятым в Bash.

echo "Логические операции"
echo

x=24
y=25
b=`expr $x = $y`         # Сравнение.
echo "b = $b"            # 0  ( $x -ne $y )
echo

a=3
b=`expr $a \&gt; 10`
echo 'b=`expr $a \&gt; 10`, поэтому...'
echo "Если a &gt; 10, то b = 0 (ложь)"
echo "b = $b"            # 0  ( 3 ! -gt 10 )
echo

b=`expr $a \&lt; 10`
echo "Если a &lt; 10, то b = 1 (истина)"
echo "b = $b"            # 1  ( 3 -lt 10 )
echo
# Обратите внимание на необходимость экранирования операторов.

b=`expr $a \&lt;= 3`
echo "Если a &lt;= 3, то b = 1 (истина)"
echo "b = $b"            # 1  ( 3 -le 3 )
# Существует еще оператор "\&gt;=" (больше или равно).


echo
echo

# Операции сравнения
# -------- ---------

echo "Операции сравнения"
echo
a=zipper
echo "a is $a"
if [ `expr $a = snap` ]
then
   echo "a -- это не zipper"
fi

echo
echo



# Операции со строками
# -------- -- --------

echo "Операции со строками"
echo

a=1234zipper43231
echo "Строка над которой производятся операции: \"$a\"."

# length: длина строки
b=`expr length $a`
echo "длина строки \"$a\" равна $b."

# index: позиция первого символа подстроки в строке
b=`expr index $a 23`
echo "Позиция первого символа \"2\" в строке \"$a\" : \"$b\"."

# substr: извлечение подстроки, начиная с заданной позиции, указанной длины
b=`expr substr $a 2 6`
echo "Подстрока в строке \"$a\", начиная с позиции 2,\
и длиной в 6 символов: \"$b\"."


#  При выполнении поиска по шаблону, по-умолчанию поиск
#+ начинается с ***начала*** строки.
#
#        Использование регулярных выражений
b=`expr match "$a" '[0-9]*'`               #  Подсчет количества цифр.
echo Количество цифр с начала строки \"$a\" : $b.
b=`expr match "$a" '\([0-9]*\)'`           #  Обратите внимание на экранирование круглых скобок
#                   ==      ==
echo "Цифры, стоящие в начале строки \"$a\" : \"$b\"."

echo

exit 0
</pre>
                  </div>

                  <div class="IMPORTANT">
                    <table class="IMPORTANT" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/important.gif" hspace="5" alt="Important"></td>

                        <td align="left" valign="top">
                          <p>Вместо оператора <strong class="COMMAND">match</strong> можно
                          использовать оператор <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#NULLREF">:</a>. Например, команда <code class="USERINPUT"><strong>b=`expr $a :
                          [0-9]*`</strong></code> является точным
                          эквивалентом для <code class="USERINPUT"><strong>b=`expr match $a
                          [0-9]*`</strong></code> в примере,
                          рассмотренном выше.</p>
<pre class="PROGRAMLISTING">#!/bin/bash

echo
echo "Операции над строками с использованием конструкции \"expr \$string : \" "
echo "========================================================================"
echo

a=1234zipper5FLIPPER43231

echo "Строка, над которой выполняются операции: \"`expr "$a" : '\(.*\)'`\"."
#     Экранирование круглых скобок в шаблоне                    ==  ==


#  Если скобки не экранировать...
#+ то 'expr' преобразует строковый операнд в целое число.

echo "Длина строки \"$a\" равна `expr "$a" : '.*'`."   # Длина строки

echo "Количество цифр с начала строки \"$a\" равно `expr "$a" : '[0-9]*'`."

# ------------------------------------------------------------------------- #

echo

echo "Цифры, стоящие в начале строки \"$a\" : `expr "$a" : '\([0-9]*\)'`."
#                                                             ==      ==
echo "Первые 7 символов в строке \"$a\" : `expr "$a" : '\(.......\)'`."
#     ======                                          ==       ==
# Опять же, необходимо экранировать круглые скобки в шаблоне.
#
echo "Последние 7 символов в строке \"$a\" : `expr "$a" : '.*\(.......\)'`."
#     =========                  оператор конца строки     ^^
#  (фактически означает переход через любое количество символов, пока
#+  не будет найдена требуемая подстрока)

echo

exit 0
</pre>
                          <br>
                          <br>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>
              </dl>
            </div>

            <p>Этот пример демонстрирует необходимость <span class="emphasis"><em class="EMPHASIS">экранирования оператора группировки -- \(
            ... \)</em></span> в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REGEXREF">регулярных выражениях</a>, при поиске по
            шаблону командой <strong class="COMMAND">expr</strong>.</p>

            <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PERLREF">Perl</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SEDREF">sed</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AWKREF">awk</a> имеют в своем распоряжении более
            мощный аппарат анализа строк. Коротенький скрипт на <strong class="COMMAND">sed</strong> или <strong class="COMMAND">awk</strong>, внутри сценария (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WRAPPER">Section 33.2</a>) -- значительно более
            привлекательная альтернатива использованию <strong class="COMMAND">expr</strong> при анализе строк.</p>

            <p>Дополнительные примеры, по обработке строк, вы найдете в
            <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#STRING-MANIPULATION">Section 9.2</a>.</p>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="TIMEDATE"></a>12.3. Команды для работы с датой и
            временем</h2>

            <div class="VARIABLELIST">
              <p><strong><a name="TDLISTING1"></a>Время/дата и измерение интервалов
              времени</strong></p>

              <dl>
                <dt><a name="DATEREF"></a><strong class="COMMAND">date</strong></dt>

                <dd>
                  <p>Команда <strong class="COMMAND">date</strong> без параметров выводит
                  дату и время на стандартное устройство вывода <code class="FILENAME">stdout</code>. Она становится гораздо
                  интереснее при использовании дополнительных ключей
                  форматирования вывода.</p>

                  <div class="EXAMPLE">
                    <a name="EX51"></a>

                    <p><strong>Пример 12-7. Команда date</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Примеры использования команды 'date'

echo "Количество дней, прошедших с начала года: `date +%j`."
# Символ '+' обязателен при использовании форматирующего аргумента
# %j,  возвращающего количество дней, прошедших с начала года.

echo "Количество секунд, прошедших с 01/01/1970 : `date +%s`."
#  %s количество секунд, прошедших с начала "эпохи UNIX",
#+ но насколько этот ключ полезен?

prefix=temp
suffix=`eval date +%s`  # Ключ "+%s" характерен для GNU-версии 'date'.
filename=$prefix.$suffix
echo $filename
#  Прекрасный способ получения "уникального" имени для временного файла,
#+ даже лучше, чем с использованием $$.

# Дополнительную информацию вы найдете в 'man date'.

exit 0
</pre>
                  </div>

                  <p>Ключ <code class="OPTION">-u</code> дает UTC время (Universal
                  Coordinated Time -- время по Гринвичу).</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>date</strong></code>
<code class="COMPUTEROUTPUT">Fri Mar 29 21:07:39 MST 2002</code>


<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>date -u</strong></code>
<code class="COMPUTEROUTPUT">Sat Mar 30 04:07:42 UTC 2002</code>
             
</pre>
                  <br>
                  <br>
                </dd>

                <dt><strong class="COMMAND">zdump</strong></dt>

                <dd>
                  <p>Отображает время для указанной временной зоны.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>zdump EST</strong></code>
<code class="COMPUTEROUTPUT">EST  Tue Sep 18 22:09:22 2001 EST</code>
             
</pre>
                  <br>
                  <br>
                </dd>

                <dt><a name="TIMREF"></a><strong class="COMMAND">time</strong></dt>

                <dd>
                  <p>Выводит подробную статистику по исполнению
                  некоторой команды.</p>

                  <p><code class="USERINPUT"><strong>time ls -l /</strong></code>
                  даст нечто подобное:</p>
<pre class="SCREEN"><code class="COMPUTEROUTPUT">0.00user 0.01system 0:00.05elapsed 16%CPU (0avgtext+0avgdata 0maxresident)k
 0inputs+0outputs (149major+27minor)pagefaults 0swaps</code>
</pre>
                  <br>
                  <br>

                  <p>См. так же очень похожую команду <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TIMESREF">times</a>, обсуждавшуюся в
                  предыдущем разделе.</p>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p>Начиная с <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BASH2REF">версии 2.0</a> Bash,
                          команда <strong class="COMMAND">time</strong> стала
                          зарезервированным словом интерпретатора, с
                          несколько измененным поведением в
                          конвейере.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><a name="TOUC"></a><strong class="COMMAND">touch</strong></dt>

                <dd>
                  <p>Утилита устанавливает время последнего
                  обращения/изменения файла в текущее системное время
                  или в заданное время, но так же может использоваться
                  для создания нового пустого файла. Команда <code class="USERINPUT"><strong>touch zzz</strong></code>
                  создаст новый пустой файл с именем <code class="FILENAME">zzz</code>, если перед этим файл <code class="FILENAME">zzz</code> отсутствовал. Кроме того,
                  такие пустые файлы могут использоваться для
                  индикации, например, времени последнего изменения в
                  проекте.</p>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p>Эквивалентом команды <strong class="COMMAND">touch</strong> могут служить
                          <code class="USERINPUT"><strong>: &gt;&gt;
                          newfile</strong></code> или <code class="USERINPUT"><strong>&gt;&gt;
                          newfile</strong></code> (для обычных
                          файлов).</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><a name="ATREF"></a><strong class="COMMAND">at</strong></dt>

                <dd>
                  <p>Команда <strong class="COMMAND">at</strong> -- используется для
                  запуска заданий в заданное время. В общих чертах она
                  напоминает <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CRONREF">crond</a>, однако, <strong class="COMMAND">at</strong> используется для
                  однократного запуска набора команд.</p>

                  <p><code class="USERINPUT"><strong>at 2pm January
                  15</strong></code> -- попросит ввести набор команд,
                  которые необходимо запустить в указанное время. Эти
                  команды должны быть совместимыми со сценариями
                  командной оболочки. Ввод завершается нажатием
                  комбинации клавиш <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CTLDREF">Ctl-D</a>.</p>

                  <p>Ключ <code class="OPTION">-f</code> или операция перенаправления
                  ввода (<span class="TOKEN">&lt;</span>), заставляет <strong class="COMMAND">at</strong> прочитать список команд
                  из файла. Этот файл должен представлять из себя
                  обычный сценарий, на языке командной оболочки и, само
                  собой разумеется, такой сценарий должен быть
                  неинтерактивным. Может использоваться совместно с
                  командой <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RUNPARTSREF">run-parts</a> для запуска
                  различных наборов сценариев.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>at 2:30 am Friday &lt; at-jobs.list</strong></code>
<code class="COMPUTEROUTPUT">job 2 at 2000-10-27 02:30</code>
             
</pre>
                  <br>
                  <br>
                </dd>

                <dt><strong class="COMMAND">batch</strong></dt>

                <dd>
                  <p>Команда <strong class="COMMAND">batch</strong>, управляющая запуском
                  заданий, напоминает команду <strong class="COMMAND">at</strong>, но запускает список
                  команд только тогда, когда загруженность системы
                  упадет ниже <code class="LITERAL">.8</code>. Подобно команде <strong class="COMMAND">at</strong>, с ключом <code class="OPTION">-f</code>, может считывать набор команд
                  из файла.</p>
                </dd>

                <dt><strong class="COMMAND">cal</strong></dt>

                <dd>
                  <p>Выводит на <code class="FILENAME">stdout</code> аккуратно
                  отформатированный календарь на текущий месяц. Может
                  выводить календарь за определенный год.</p>
                </dd>

                <dt><strong class="COMMAND">sleep</strong></dt>

                <dd>
                  <p>Приостанавливает исполнение сценария на заданное
                  количество секунд, ничего не делая. Может
                  использоваться для синхронизации процессов,
                  запущенных в фоне, проверяя наступление ожидаемого
                  события так часто, как это необходимо. Например, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ONLINE">Пример 29-6</a>.</p>
<pre class="PROGRAMLISTING">sleep 3
# Пауза, длительностью в 3 секунды.
</pre>
                  <br>
                  <br>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p>Команда <strong class="COMMAND">sleep</strong> по-умолчанию
                          принимает количество секунд, но ей можно
                          передать и количество часов и минут и даже
                          дней.</p>
<pre class="PROGRAMLISTING">sleep 3 h
# Приостановка на 3 часа!
</pre>
                          <br>
                          <br>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p>Для запуска команд через заданные
                          интервалы времени лучше использовать <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WATCHREF">watch</a> .</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><strong class="COMMAND">usleep</strong></dt>

                <dd>
                  <p><span class="emphasis"><em class="EMPHASIS">Microsleep</em></span> (здесь
                  символ <span class="QUOTE">"u"</span> должен читаться
                  как буква греческого алфавита -- <span class="QUOTE">"мю"</span>, или префикс
                  микро). Это то же самое, что и <strong class="COMMAND">sleep</strong>, только интервал
                  времени задается в микросекундах. Может
                  использоваться для очень тонкой синхронизации
                  процессов.</p>
<pre class="PROGRAMLISTING">usleep 30
# Приостановка на 30 микросекунд.
</pre>
                  <br>
                  <br>

                  <p>Эта команда является частью пакета <span class="emphasis"><em class="EMPHASIS">initscripts/rc-scripts</em></span>
                  в дистрибутиве Red Hat.</p>

                  <div class="CAUTION">
                    <table class="CAUTION" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                        <td align="left" valign="top">
                          <p>Команда <strong class="COMMAND">usleep</strong> не
                          обеспечивает особую точность соблюдения
                          интервалов, и поэтому она не подходит для
                          применений, критичных ко времени.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><strong class="COMMAND">hwclock</strong>, <strong class="COMMAND">clock</strong></dt>

                <dd>
                  <p>Команда <strong class="COMMAND">hwclock</strong> используется для
                  получения доступа или коррекции аппаратных часов
                  компьютера. С некоторыми ключами требует наличия
                  привилегий root. Сенарий <code class="FILENAME">/etc/rc.d/rc.sysinit</code>
                  использует команду <strong class="COMMAND">hwclock</strong> для установки
                  системного времени во время загрузки.</p>

                  <p>Команда <strong class="COMMAND">clock</strong> -- это синоним
                  команды <strong class="COMMAND">hwclock</strong>.</p>
                </dd>
              </dl>
            </div>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="TEXTPROC"></a>12.4. Команды обработки текста</h2>

            <div class="VARIABLELIST">
              <p><strong><a name="TPCOMMANDLISTING1"></a></strong></p>

              <dl>
                <dt><a name="SORTREF"></a><strong class="COMMAND">sort</strong></dt>

                <dd>
                  <p>Сортирует содержимое файла, часто используется как
                  промежуточный фильтр в конвейерах. Эта команда
                  сортирует поток текста в порядке убывания или
                  возрастания, в зависимости от заданных опций. Ключ
                  <code class="OPTION">-m</code> используется для сортировки и
                  объединения входных файлов. В <span class="emphasis"><em class="EMPHASIS">странице info</em></span>
                  перечислено большое количество возможных вариантов
                  ключей. См. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FINDSTRING">Пример 10-9</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SYMLINKS">Пример 10-10</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MAKEDICT">Пример A-9</a>.</p>
                </dd>

                <dt><strong class="COMMAND">tsort</strong></dt>

                <dd>
                  <p>Топологическая сортировка, считывает пары строк,
                  разделенных пробельными символами, и выполняет
                  сортировку, в зависимости от заданного шаблона.</p>
                </dd>

                <dt><a name="UNIQREF"></a><strong class="COMMAND">uniq</strong></dt>

                <dd>
                  <p>Удаляет повторяющиеся строки из отсортированного
                  файла. Эту команду часто можно встретить в конвейере
                  с командой <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SORTREF">sort</a>.</p>
<pre class="PROGRAMLISTING">cat list-1 list-2 list-3 | sort | uniq &gt; final.list
# Содержимое файлов,
# сортируется,
# затем удаляются повторяющиеся строки,
# и результат записывается в выходной файл.
</pre>
                  <br>
                  <br>

                  <p>Ключ <code class="OPTION">-c</code> выводит количество
                  повторяющихся строк.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>cat testfile</strong></code>
<code class="COMPUTEROUTPUT">Эта строка встречается только один раз.
Эта строка встречается дважды.
Эта строка встречается дважды.
Эта строка встречается трижды.
Эта строка встречается трижды.
Эта строка встречается трижды.</code>


<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>uniq -c testfile</strong></code>
<code class="COMPUTEROUTPUT">1 Эта строка встречается только один раз.
2 Эта строка встречается дважды.
3 Эта строка встречается трижды.</code>


<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>sort testfile | uniq -c | sort -nr</strong></code>
<code class="COMPUTEROUTPUT">3 Эта строка встречается трижды.
2 Эта строка встречается дважды.
1 Эта строка встречается только один раз.</code>
             
</pre>
                  <br>
                  <br>

                  <p>Команда <code class="USERINPUT"><strong>sort INPUTFILE | uniq -c |
                  sort -nr</strong></code> выводит <span class="emphasis"><em class="EMPHASIS">статистику
                  встречаемости</em></span> строк в файле <code class="FILENAME">INPUTFILE</code> (ключ <code class="OPTION">-nr</code>, в команде <strong class="COMMAND">sort</strong>, означает сортировку в
                  порядке убывания). Этот шаблон может с успехом
                  использоваться при анализе файлов системного журнала,
                  словарей и везде, где необходимо проанализировать
                  лексическую структуру документа.</p>

                  <div class="EXAMPLE">
                    <a name="WF"></a>

                    <p><strong>Пример 12-8. Частота встречаемости
                    отдельных слов</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# wf.sh: "Сырой" анализ частоты встречаемости слова в текстовом файле.


ARGS=1
E_BADARGS=65
E_NOFILE=66

if [ $# -ne "$ARGS" ]  # Файл для анализа задан?
then
  echo "Порядок использования: `basename $0` filename"
  exit $E_BADARGS
fi

if [ ! -f "$1" ]       # Проверка существования файла.
then
  echo "Файл \"$1\" не найден."
  exit $E_NOFILE
fi



########################################################
# main ()
sed -e 's/\.//g'  -e 's/ /\
/g' "$1" | tr 'A-Z' 'a-z' | sort | uniq -c | sort -nr
#                           =========================
#                         Подсчет количества вхождений

#  Точки и пробелы заменяются
#+ символами перевода строки,
#+ затем символы переводятся в нижний регистр
#+ и наконец подсчитывается количество вхождений,
#+ и выполняется сортировка по числу вхождений.
########################################################

# Упражнения:
# ---------
# 1) Добавьте команду 'sed' для отсечения других знаков пунктуации, например, запятых.
# 2) Добавьте удаление лишних пробелов и других пробельных символов.
# 3) Добавьте дополнительную сортировку так, чтобы слова с одинаковой частотой встречаемости
#+   сортировались бы в алфавитном порядке.

exit 0
</pre>
                  </div>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>cat testfile</strong></code>
<code class="COMPUTEROUTPUT">Эта строка встречается только один раз.
Эта строка встречается дважды.
Эта строка встречается дважды.
Эта строка встречается трижды.
Эта строка встречается трижды.
Эта строка встречается трижды.</code>


<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>./wf.sh testfile</strong></code>
 <code class="COMPUTEROUTPUT">      6 Эта
       6 встречается
       6 строка
       3 трижды
       2 дважды
       1 только
       1 один
       1 раз
                        </code> 
              
</pre>
                  <br>
                  <br>
                </dd>

                <dt><a name="EXPANDREF"></a><strong class="COMMAND">expand</strong>, <strong class="COMMAND">unexpand</strong></dt>

                <dd>
                  <p>Команда <strong class="COMMAND">expand</strong> преобразует символы
                  табуляции в пробелы. Часто используется в конвейерной
                  обработке текста.</p>

                  <p>Команда <strong class="COMMAND">unexpand</strong> преобразует
                  пробелы в символы табуляции. Т.е. она является
                  обратной по отношению к команде <strong class="COMMAND">expand</strong>.</p>
                </dd>

                <dt><a name="CUTREF"></a><strong class="COMMAND">cut</strong></dt>

                <dd>
                  <p>Предназначена для извлечения отдельных полей из
                  текстовых файлов. Напоминает команду <code class="USERINPUT"><strong>print $N</strong></code> в
                  <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AWKREF">awk</a>, но более ограничена в своих
                  возможностях. В простейших случаях может быть
                  неплохой заменой <strong class="COMMAND">awk</strong> в сценариях. Особую
                  значимость, для команды <strong class="COMMAND">cut</strong>, представляют ключи <code class="OPTION">-d</code> (разделитель полей) и <code class="OPTION">-f</code> (номер(а) поля(ей)).</p>

                  <p>Использование команды <strong class="COMMAND">cut</strong> для получения списка
                  смонтированных файловых систем:</p>
<pre class="PROGRAMLISTING">cat /etc/mtab | cut -d ' ' -f1,2
</pre>
                  <br>
                  <br>

                  <p>Использование команды <strong class="COMMAND">cut</strong> для получения версии ОС
                  и ядра:</p>
<pre class="PROGRAMLISTING">uname -a | cut -d" " -f1,3,11,12
</pre>
                  <br>
                  <br>

                  <p>Использование команды <strong class="COMMAND">cut</strong> для извлечения
                  заголовков сообщений из электронных писем:</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>grep '^Subject:' read-messages | cut -c10-80</strong></code>
<code class="COMPUTEROUTPUT">Re: Linux suitable for mission-critical apps?
 MAKE MILLIONS WORKING AT HOME3
 Spam complaint
 Re: Spam complaint</code>
</pre>
                  <br>
                  <br>

                  <p>Использование команды <strong class="COMMAND">cut</strong> при разборе текстового
                  файла:</p>
<pre class="PROGRAMLISTING"># Список пользователей в /etc/passwd.

FILENAME=/etc/passwd

for user in $(cut -d: -f1 $FILENAME)
do
  echo $user
done

# Спсибо Oleg Philon за этот пример.
</pre>
                  <br>
                  <br>

                  <p><code class="USERINPUT"><strong>cut -d ' ' -f2,3
                  filename</strong></code> эквивалентно <code class="USERINPUT"><strong>awk -F'[ ]' '{
                  print $2, $3 }' filename</strong></code></p>

                  <p>См. также <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BASE">Пример 12-33</a>.</p>
                </dd>

                <dt><strong class="COMMAND">paste</strong></dt>

                <dd>
                  <p>Используется для объединения нескольких файлов в
                  один многоколоночный файл.</p>
                </dd>

                <dt><strong class="COMMAND">join</strong></dt>

                <dd>
                  <p>Может рассматриваться как команда, родственная
                  команде <strong class="COMMAND">paste</strong>. Эта мощная утилита
                  позволяет объединять два файла по общему полю, что
                  представляет собой упрощенную версию реляционной базы
                  данных.</p>

                  <p>Команда <strong class="COMMAND">join</strong> оперирует только двумя
                  файлами и объедияет только те строки, которые имеют
                  общее поле (обычно числовое), результат объединения
                  выводится на <code class="FILENAME">stdout</code>. Объединяемые файлы
                  должны быть отсортированы по ключевому полю.</p>
<pre class="PROGRAMLISTING">File: 1.data

100 Shoes
200 Laces
300 Socks
</pre>
                  <br>
                  <br>
<pre class="PROGRAMLISTING">File: 2.data

100 $40.00
200 $1.00
300 $2.00
</pre>
                  <br>
                  <br>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>join 1.data 2.data</strong></code>
<code class="COMPUTEROUTPUT">File: 1.data 2.data

100 Shoes $40.00
200 Laces $1.00
300 Socks $2.00</code>
             
</pre>
                  <br>
                  <br>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p>На выходе ключевое поле встречается только
                          один раз.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><strong class="COMMAND">head</strong></dt>

                <dd>
                  <p>Выводит начальные строки из файла на <code class="FILENAME">stdout</code> (по-умолчанию -- <code class="LITERAL">10</code> строк, но это число можно
                  задать иным). Эта команда имеет ряд интересных
                  ключей.</p>

                  <div class="EXAMPLE">
                    <a name="SCRIPTDETECTOR"></a>

                    <p><strong>Пример 12-9. Какие из файлов являются
                    сценариями?</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# script-detector.sh: Отыскивает файлы сценариев в каталоге.

TESTCHARS=2    # Проверяются первые два символа.
SHABANG='#!'   # Сценарии как правило начинаются с "sha-bang."

for file in *  # Обход всех файлов в каталоге.
do
  if [[ `head -c$TESTCHARS "$file"` = "$SHABANG" ]]
  #      head -c2                      #!
  #  Ключ '-c' в команде "head" выводит заданное
  #+ количество символов, а не строк.
  then
    echo "Файл \"$file\" -- сценарий."
  else
    echo "Файл \"$file\" не является сценарием."
  fi
done
  
exit 0
</pre>
                  </div>

                  <div class="EXAMPLE">
                    <a name="RND"></a>

                    <p><strong>Пример 12-10. Генератор 10-значных
                    случайных чисел</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# rnd.sh: Генератор 10-значных случайных чисел

# Автор: Stephane Chazelas.

head -c4 /dev/urandom | od -N4 -tu4 | sed -ne '1s/.* //p'


# =================================================================== #

# Описание
# --------

# head:
# -c4 -- первые 4 байта.

# od:
# -N4 ограничивает вывод 4-мя байтами.
# -tu4 беззнаковый десятичный формат вывода.

# sed:
# -n, в комбинации с флагом "p", в команде "s",
# выводит только совпадающие с шаблоном строки.



# Автор сценария описывает действия 'sed' таким образом:

# head -c4 /dev/urandom | od -N4 -tu4 | sed -ne '1s/.* //p'
# ----------------------------------&gt; |

# Передает вывод в "sed"    --------&gt; |
# пусть это будет 0000000 1198195154\n

# sed начинает читать символы: 0000000 1198195154\n.
# Здесь он находит символ перевода строки,
# таким образом он получает строку (0000000 1198195154).
# Затем он просматривает &lt;диапазон&gt;&lt;действие&gt;. Первый и единственный -- это

#   диапазон  действие
#   1         s/.* //p

# Номер строки попадает в заданный лиапазон, так что теперь он приступает к выполнению действия:
# пытается заменить наибольшую подстроку, заканчивающуюся пробелом
# ("0000000 ") "ничем" (//), и если замена произведена -- выводит результат
# ("p" -- это флаг команды "s", а не команда "p", которая имеет иное значение).

# теперь sed готов продолжить чтение входного потока. (Обратите внимание:
# если опустить ключ -n, то sed выведет строку еще раз)

# Теперь sed дочитывает остаток строки.
# Он готов приступить к анализу 2-й строки (которая отмечена '$'
# как последняя).
# Поскольку строка не попадает в заданный &lt;диапазон&gt;, на этом обработка прекращается.

# Проще говоря, команда sed означает:
# "В первой строке удалить любые символы, вплоть до последнего встреченного пробела,
# и затем вывести остаток."

# Сделать это можно более простым способом:
#           sed -e 's/.* //;q'

# Где, заданы два &lt;диапазона&gt;&lt;действия&gt; (можно записать и по другому
#           sed -e 's/.* //' -e q):

#   диапазон                          действие
#   ничего (для совпадающих строк)    s/.* //
#   ничего (для совпадающих строк)    q (quit)

# Здесь sed считывает только первую строку.
# Выполняет оба действия, и выводит строку перед завершением
# (действие "q"), поскольку ключ "-n" опущен.

# =================================================================== #

# Простая альтернатива:
#           head -c4 /dev/urandom| od -An -tu4

exit 0
</pre>
                  </div>
                  См. также <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX52">Пример 12-30</a>.<br>
                  <br>
                </dd>

                <dt><strong class="COMMAND">tail</strong></dt>

                <dd>
                  <p>Выводит последние строки из файла на <code class="FILENAME">stdout</code> (по-умолчанию -- 10
                  строк). Обычно используется для мониторинга системных
                  журналов. Ключ <code class="OPTION">-f</code>, позволяет вести непрерывное
                  наблюдение за добавляемыми строками в файл.</p>

                  <div class="EXAMPLE">
                    <a name="EX12"></a>

                    <p><strong>Пример 12-11. Мониторинг системного
                    журнала с помощью tail</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

filename=sys.log

cat /dev/null &gt; $filename; echo "Создание / очистка временного файла."
#  Если файл отсутствует, то он создается,
#+ и очищается, если существует.
#  : &gt; filename   и   &gt; filename дают тот же эффект.

tail /var/log/messages &gt; $filename
# Файл /var/log/messages должен быть доступен для чтения.

echo "В файл $filename записаны последние строки из /var/log/messages."

exit 0
</pre>
                  </div>

                  <p>См. также <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX41">Пример 12-4</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX52">Пример 12-30</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ONLINE">Пример 29-6</a>.</p>
                </dd>

                <dt><a name="GREPREF"></a><strong class="COMMAND">grep</strong></dt>

                <dd>
                  <p>Многоцелевая поисковая утилита, использующая <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REGEXREF">регулярные выражения</a>.
                  Изначально это была команда в древнем строчном
                  редакторе <strong class="COMMAND">ed</strong>, <code class="USERINPUT"><strong>g/re/p</strong></code>, что
                  означает -- <span class="emphasis"><em class="EMPHASIS">global - regular expression -
                  print</em></span>.</p>

                  <p><strong class="COMMAND">grep</strong> <code class="REPLACEABLE"><em>pattern</em></code> [<code class="REPLACEABLE"><em>file</em></code>...]</p>
                  Поиск участков текста в файле(ах), соответствующих
                  шаблону <code class="REPLACEABLE"><em>pattern</em></code>, где <code class="REPLACEABLE"><em>pattern</em></code> может быть
                  как обычной строкой, так и регулярным выражением.<br>
                  <br>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>grep '[rst]ystem.$' osinfo.txt</strong></code>
<code class="COMPUTEROUTPUT">The GPL governs the distribution of the Linux operating system.</code>
             
</pre>
                  <br>
                  <br>

                  <p>Если файл(ы) для поиска не задан, то команда
                  <strong class="COMMAND">grep</strong> работает как фильтр
                  для устройства <code class="FILENAME">stdout</code>, например в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PIPEREF">конвейере</a>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>ps ax | grep clock</strong></code>
<code class="COMPUTEROUTPUT">765 tty1     S      0:00 xclock
 901 pts/1    S      0:00 grep clock</code>
             
</pre>
                  <br>
                  <br>

                  <p><code class="OPTION">-i</code> -- выполняется поиск без
                  учета регистра символов.</p>

                  <p><code class="OPTION">-w</code> -- поиск совпадений целого
                  слова.</p>

                  <p><code class="OPTION">-l</code> -- вывод только имен файлов,
                  в которых найдены участки, совпадающие с заданным
                  образцом/шаблоном, без вывода совпадающих строк.</p>

                  <p><code class="OPTION">-r</code> -- (рекурсивный поиск) поиск
                  выполняется в текущем каталоге и всех вложенных
                  подкаталогах.</p>

                  <p>The <code class="OPTION">-n</code> option lists the matching
                  lines, together with line numbers.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>grep -n Linux osinfo.txt</strong></code>
<code class="COMPUTEROUTPUT">2:This is a file containing information about Linux.
 6:The GPL governs the distribution of the Linux operating system.</code>
             
</pre>
                  <br>
                  <br>

                  <p><code class="OPTION">-v</code> (или <code class="OPTION">--invert-match</code>) -- выводит
                  только строки, не содержащие совпадений.</p>
<pre class="PROGRAMLISTING">grep pattern1 *.txt | grep -v pattern2

# Выводятся строки из "*.txt", совпадающие с "pattern1",
# но ***не*** совпадающие с "pattern2".
</pre>
                  <br>
                  <br>

                  <p><code class="OPTION">-c</code> (<code class="OPTION">--count</code>) -- выводит количество
                  совпадений без вывода самих совпадений.</p>
<pre class="PROGRAMLISTING">grep -c txt *.sgml   # (количество совпадений с "txt" в "*.sgml" файлах)


#   grep -cz .
#            ^ точка
# означает подсчет (-c) непустых ("." -- содержащих хотя бы один символ) элементов,
# разделенных нулевыми байтами (-z)
#
printf 'a b\nc  d\n\n\n\n\n\000\n\000e\000\000\nf' | grep -cz .     # 4
printf 'a b\nc  d\n\n\n\n\n\000\n\000e\000\000\nf' | grep -cz '$'   # 5
printf 'a b\nc  d\n\n\n\n\n\000\n\000e\000\000\nf' | grep -cz '^'   # 5
#
printf 'a b\nc  d\n\n\n\n\n\000\n\000e\000\000\nf' | grep -c '$'    # 9
# По-умолчанию, в качестве разделителя, принимается символ перевода строки (\n).

# Обратите внимание: ключ -z характерен для GNU-версии "grep".


# Спасибо S.C.
</pre>
                  <br>
                  <br>

                  <p>Если <strong class="COMMAND">grep</strong> вызывается для поиска
                  по группе файлов, то вывод будет содержать указание
                  на имена файлов, в которых найдены совпадения.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>grep Linux osinfo.txt misc.txt</strong></code>
<code class="COMPUTEROUTPUT">osinfo.txt:This is a file containing information about Linux.
 osinfo.txt:The GPL governs the distribution of the Linux operating system.
 misc.txt:The Linux operating system is steadily gaining in popularity.</code>
             
</pre>
                  <br>
                  <br>

                  <div class="TIP">
                    <table class="TIP" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/tip.gif" hspace="5" alt="Tip"></td>

                        <td align="left" valign="top">
                          <p>Для того, чтобы заставить <strong class="COMMAND">grep</strong> выводить имя
                          файла, когда поиск производится по
                          одному-единственному файлу, достаточно
                          указать устройство <code class="FILENAME">/dev/null</code> в качестве
                          второго файла.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>grep Linux osinfo.txt /dev/null</strong></code>
<code class="COMPUTEROUTPUT">osinfo.txt:This is a file containing information about Linux.
 osinfo.txt:The GPL governs the distribution of the Linux operating system.</code>
             
</pre>
                          <br>
                          <br>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>

                  <p>Если совпадение было найдено, то <strong class="COMMAND">grep</strong> возвращает <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXITSTATUSREF">код завершения</a> -- 0, это
                  может оказаться полезным при выполнении поиска в
                  условных операторах ( в таких случаях особый интерес
                  может представлять ключ <code class="OPTION">-q</code>, который подавляет
                  вывод).</p>
<pre class="PROGRAMLISTING">SUCCESS=0                      # если найдено совпадение
word=Linux
filename=data.file

grep -q "$word" "$filename"    # "-q" -- подавляет вывод на stdout.

if [ $? -eq $SUCCESS ]
then
  echo "Образец $word найден в $filename"
else
  echo "Образец $word в файле $filename не найден"
fi
</pre>
                  <br>
                  <br>

                  <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ONLINE">Пример 29-6</a> -- пример поиска
                  заданного образца в системном журнале, с помощью
                  <strong class="COMMAND">grep</strong>.</p>

                  <div class="EXAMPLE">
                    <a name="GRP"></a>

                    <p><strong>Пример 12-12. Сценарий-эмулятор <span class="QUOTE">"grep"</span></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# grp.sh: Очень "грубая" реализация 'grep'.

E_BADARGS=65

if [ -z "$1" ]    # Проверка наличия аргументов.
then
  echo "Порядок использования: `basename $0` pattern"
  exit $E_BADARGS
fi

echo

for file in *     # Обход всех файлов в $PWD.
do
  output=$(sed -n /"$1"/p $file)  # Подстановка команд.

  if [ ! -z "$output" ]           # Что произойдет, если кавычки вокруг "$output" убрать?
  then
    echo -n "$file: "
    echo $output
  fi              #  эквивалент: sed -ne "/$1/s|^|${file}: |p"

  echo
done

echo

exit 0

# Упражнения:
# ---------
# 1) Добавьте вывод символов перевода строки, если найдено более одного совпадения в любом из файлов.
# 2) Добавьте обработку различных ключей.
</pre>
                  </div>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p><a name="EGREPREF"></a><strong class="COMMAND">egrep</strong> -- то же
                          самое, что и <strong class="COMMAND">grep -E</strong>. Эта
                          команда использует несколько отличающийся,
                          расширенный набор <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REGEXREF">регулярных выражений</a>,
                          что позволяет выполнять поиск более
                          гибко.</p>

                          <p><strong class="COMMAND">fgrep</strong> -- то же
                          самое, что и <strong class="COMMAND">grep -F</strong>. Эта
                          команда выполняет поиск строк символов (не
                          регулярных выражений), что несколько
                          увеличивает скорость поиска.</p>

                          <p>Утилита <strong class="COMMAND">agrep</strong> имеет более
                          широкие возможности поиска приблизительных
                          совпадений. Образец поиска может отличаться
                          от найденной строки на указанное число
                          символов.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>

                  <div class="TIP">
                    <table class="TIP" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/tip.gif" hspace="5" alt="Tip"></td>

                        <td align="left" valign="top">
                          <p>Для поиска по сжатым файлам следует
                          использовать утилиты <strong class="COMMAND">zgrep</strong>, <strong class="COMMAND">zegrep</strong> или <strong class="COMMAND">zfgrep</strong>. Они с
                          успехом могут использоваться и для не сжатых
                          файлов, но в этом случае они уступают в
                          скорости обычным <strong class="COMMAND">grep</strong>, <strong class="COMMAND">egrep</strong> и <strong class="COMMAND">fgrep</strong>. Они очень
                          удобны при выполнении поиска по смешенному
                          набору файлов -- когда одни файлы сжаты, а
                          другие нет.</p>

                          <p>Для поиска по <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BZIPREF">bzip</a>-файлам используйте
                          <strong class="COMMAND">bzgrep</strong>.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><strong class="COMMAND">look</strong></dt>

                <dd>
                  <p>Команда <strong class="COMMAND">look</strong> очень похожа на
                  <strong class="COMMAND">grep</strong>, и предназначена для
                  поиска по <span class="QUOTE">"словарям"</span> --
                  отсортированным файлам. По-умолчанию, поиск
                  выполняется в файле <code class="FILENAME">/usr/dict/words</code>, но может быть
                  указан и другой словарь.</p>

                  <div class="EXAMPLE">
                    <a name="LOOKUP"></a>

                    <p><strong>Пример 12-13. Поиск слов в
                    словаре</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# lookup: Выполняется поиск каждого слова из файла в словаре.

file=words.data  # Файл с искомыми словами.

echo

while [ "$word" != end ]  # Последнее слово в файле.
do
  read word      # Из файла, потому, что выполнено перенаправление в конце цикла.
  look $word &gt; /dev/null  # Подавление вывода строк из словаря.
  lookup=$?      # Код возврата команды 'look'.

  if [ "$lookup" -eq 0 ]
  then
    echo "Слово \"$word\" найдено."
  else
    echo "Слово \"$word\" не найдено."
  fi

done &lt;"$file"    # Перенаправление ввода из файла $file, так что "чтение" производится оттуда.

echo

exit 0

# ----------------------------------------------------------------
# Строки, расположенные ниже не будут исполнены, поскольку выше стоит команда "exit".


# Stephane Chazelas предложил более короткий вариант:

while read word &amp;&amp; [[ $word != end ]]
do if look "$word" &gt; /dev/null
   then echo "Слово \"$word\" найдено."
   else echo "Слово \"$word\" не найдено."
   fi
done &lt;"$file"

exit 0
</pre>
                  </div>
                </dd>

                <dt><strong class="COMMAND">sed</strong>, <strong class="COMMAND">awk</strong></dt>

                <dd>
                  <p>Скриптовые языки, специально разработанные для
                  анализа текстовых данных.</p>
                </dd>

                <dt><strong class="COMMAND"><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SEDREF">sed</a></strong></dt>

                <dd>
                  <p>Неинтерактивный <span class="QUOTE">"потоковый редактор"</span>.
                  Широко используется в сценариях на языке командной
                  оболочки.</p>
                </dd>

                <dt><strong class="COMMAND"><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AWKREF">awk</a></strong></dt>

                <dd>
                  <p>Утилита контекстного поиска и преобразования
                  текста, замечательный инструмент для извлечения и/или
                  обработки полей (колонок) в структурированных
                  текстовых файлах. Синтаксис awk напоминает язык
                  C.</p>
                </dd>

                <dt><strong class="COMMAND">wc</strong></dt>

                <dd>
                  <p><span class="emphasis"><em class="EMPHASIS">wc</em></span> -- <span class="QUOTE">"word count"</span>, счетчик
                  слов в файле или в потоке:</p>
<pre class="SCREEN"><code class="PROMPT">bash $</code> <code class="USERINPUT"><strong>wc /usr/doc/sed-3.02/README</strong></code>
<code class="COMPUTEROUTPUT">20     127     838 /usr/doc/sed-3.02/README</code>
[20 строк  127 слов  838 символов]
</pre>
                  <br>
                  <br>

                  <p><code class="USERINPUT"><strong>wc -w</strong></code>
                  подсчитывает только слова.</p>

                  <p><code class="USERINPUT"><strong>wc -l</strong></code>
                  подсчитывает только строки.</p>

                  <p><code class="USERINPUT"><strong>wc -c</strong></code>
                  подсчитывает только символы.</p>

                  <p><code class="USERINPUT"><strong>wc -L</strong></code>
                  возвращает длину наибольшей строки.</p>

                  <p>Подсчет количества <span class="emphasis"><em class="EMPHASIS">.txt</em></span>-файлов в текущем
                  каталоге с помощью <strong class="COMMAND">wc</strong>:</p>
<pre class="PROGRAMLISTING">$ ls *.txt | wc -l
# Эта команда будет работать, если ни в одном из имен файлов "*.txt" нет символа перевода строки.

# Альтернативный вариант:
#      find . -maxdepth 1 -name \*.txt -print0 | grep -cz .
#      (shopt -s nullglob; set -- *.txt; echo $#)

# Спасибо S.C.
</pre>
                  <br>
                  <br>

                  <p>Подсчет общего размера файлов, чьи имена
                  начинаются с символов, в диапазоне d - h</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>wc [d-h]* | grep total | awk '{print $3}'</strong></code>
<code class="COMPUTEROUTPUT">71832</code>
             
</pre>
                  <br>
                  <br>

                  <p>От переводчика: в случае, если у вас локаль
                  отлична от "C", то вышеприведенная команда
                  может не дать результата, поскольку <strong class="COMMAND">wc</strong> вернет не слово
                  "total", в конце вывода, а
                  "итого". Тогда можно попробовать несколько
                  измененный вариант:</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>wc [d-h]* | grep итого | awk '{print $3}'</strong></code>
<code class="COMPUTEROUTPUT">71832</code>
             
</pre>
                  <br>
                  <br>

                  <p>Использование <strong class="COMMAND">wc</strong> для подсчета количества
                  вхождений слова <span class="QUOTE">"Linux"</span> в основной
                  исходный файл с текстом этого руководства.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>grep Linux abs-book.sgml | wc -l</strong></code>
<code class="COMPUTEROUTPUT">50</code>
             
</pre>
                  <br>
                  <br>

                  <p>См. также <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX52">Пример 12-30</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REDIR4">Пример 16-7</a>.</p>

                  <p>Отдельные команды располагают функциональностью
                  <strong class="COMMAND">wc</strong> в виде своих ключей.</p>
<pre class="PROGRAMLISTING">... | grep foo | wc -l
# Часто встречающаяся конструкция, которая может быть сокращена.

... | grep -c foo
# Ключ "-c" ("--count") команды grep.

# Спасибо S.C.
</pre>
                  <br>
                  <br>
                </dd>

                <dt><a name="TRREF"></a><strong class="COMMAND">tr</strong></dt>

                <dd>
                  <p>Замена одних символов на другие.</p>

                  <div class="CAUTION">
                    <table class="CAUTION" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                        <td align="left" valign="top">
                          <p>В отдельных случаях <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#UCREF">символы необходимо заключать в
                          кавычки и/или квадратные скобки</a>. Кавычки
                          предотвращают интерпретацию специальных
                          символов командной оболочкой. Квадратные
                          скобки должны заключаться в кавычки.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>

                  <p>Команда <code class="USERINPUT"><strong>tr "A-Z"
                  "*" &lt;filename</strong></code> или <code class="USERINPUT"><strong>tr A-Z \*
                  &lt;filename</strong></code> заменяет все символы
                  верхнего регистра в <code class="FILENAME">filename</code> на звездочки (вывод
                  производится на <code class="FILENAME">stdout</code>). В некоторых системах
                  этот вариант может оказаться неработоспособным, тогда
                  попробуйте <code class="USERINPUT"><strong>tr A-Z
                  '[**]'</strong></code>.</p>

                  <p>Ключ <code class="OPTION">-d</code> удаляет символы из заданного
                  диапазона.</p>
<pre class="PROGRAMLISTING">echo "abcdef"                 # abcdef
echo "abcdef" | tr -d b-d     # aef


tr -d 0-9 &lt;filename
# Удалит все цифровые символы из файла "filename".
</pre>
                  <br>
                  <br>

                  <p>Ключ <code class="OPTION">--squeeze-repeats</code> (<code class="OPTION">-s</code>) удалит все повторяющиеся
                  последовательности символов. Может использоваться для
                  удаления лишних <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WHITESPACEREF">пробельных символов</a>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo "XXXXX" | tr --squeeze-repeats 'X'</strong></code>
<code class="COMPUTEROUTPUT">X</code>
</pre>
                  <br>
                  <br>

                  <p>Ключ <code class="OPTION">-c</code> <span class="QUOTE">"complement"</span> <span class="emphasis"><em class="EMPHASIS">заменит</em></span> символы в
                  соответствии с шаблоном. Этот ключ воздействует
                  только на те символы, которые НЕ соответствуют
                  заданному шаблону.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo "acfdeb123" | tr -c b-d +</strong></code>
<code class="COMPUTEROUTPUT">+c+d+b++++</code>
</pre>
                  <br>
                  <br>

                  <p>Обратите внимание: команда <strong class="COMMAND">tr</strong> корректно распознает <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#POSIXREF">символьные классы POSIX</a>. <a name="AEN7520" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN7520"><span class="footnote">[29]</span></a></p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo "abcd2ef1" | tr '[:alpha:]' -</strong></code>
<code class="COMPUTEROUTPUT">----2--1</code>
             
</pre>
                  <br>
                  <br>

                  <div class="EXAMPLE">
                    <a name="EX49"></a>

                    <p><strong>Пример 12-14. toupper: Преобразование
                    символов в верхний регистр.</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Преобразование символов в верхний регистр.

E_BADARGS=65

if [ -z "$1" ]  # Стандартная проверка командной строки.
then
  echo "Порядок использования: `basename $0` filename"
  exit $E_BADARGS
fi

tr a-z A-Z &lt;"$1"

# Тот же эффект можно получить при использовании символьных классов POSIX:
#        tr '[:lower:]' '[:upper:]' &lt;"$1"
# Спасибо S.C.

exit 0
</pre>
                  </div>

                  <div class="EXAMPLE">
                    <a name="LOWERCASE"></a>

                    <p><strong>Пример 12-15. lowercase: Изменение имен
                    всех файлов в текущем каталоге в нижний
                    регистр.</strong></p>
<pre class="PROGRAMLISTING">#! /bin/bash
#
# Изменит все имена файлов в текущем каталоге в нижнй регистр.
#


for filename in *                # Обход всех файлов в каталоге.
do
   fname=`basename $filename`
   n=`echo $fname | tr A-Z a-z`  # Перевести символы в нижний регистр.
   if [ "$fname" != "$n" ]       # Переименовать только те файлы, имена которых изменились.
   then
     mv $fname $n
   fi
done

exit 0


# Сироки приведенные ниже не будут исполняться, поскольку выше стоит команда "exit".
#--------------------------------------------------------#
# Запустите эту часть сценария, удалив строки , стоящие выше.

# Сценарий, приведенный выше, не работает с именами файлов, содержащими пробелы или символы перевода строки.

# В связи с этим, Stephane Chazelas предложил следующий вариант:


for filename in *    # Нет необходимости использовать basename,
                     # поскольку "*" возвращает имена, не содержащие "/".
do n=`echo "$filename/" | tr '[:upper:]' '[:lower:]'`
#                             символьные классы POSIX.
#                    Завершающий слэш добавлен для того, чтобы символ перевода строки
#                    не был удален при подстановке команды.
   # Подстановка переменной:
   n=${n%/}          # Удаление завершающего слэша, добавленного выше.
   [[ $filename == $n ]] || mv "$filename" "$n"
                     # Проверка -- действительно ли изменилось имя файла.
done

exit 0
</pre>
                  </div>

                  <div class="EXAMPLE">
                    <a name="DU"></a>

                    <p><strong>Пример 12-16. du: Преобразование
                    текстового файла из формата DOS в формат
                    UNIX.</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# du.sh: Преобразование текстового файла из формата DOS в формат UNIX.

E_WRONGARGS=65

if [ -z "$1" ]
then
  echo "Порядок использования: `basename $0` filename-to-convert"
  exit $E_WRONGARGS
fi

NEWFILENAME=$1.unx

CR='\015'  # Возврат каретки.
# Строки в текстовых файлах DOS завершаются комбинацией символов CR-LF.

tr -d $CR &lt; $1 &gt; $NEWFILENAME
# Удалить символы CR и записать в новый файл.

echo "Исходный текстовый файл: \"$1\"."
echo "Преобразованный файл: \"$NEWFILENAME\"."

exit 0
</pre>
                  </div>

                  <div class="EXAMPLE">
                    <a name="ROT13"></a>

                    <p><strong>Пример 12-17. rot13: Сверхслабое
                    шифрование по алгоритму rot13.</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# rot13.sh: Классический алгоритм шифрования rot13,
#           который способен "расколоть" даже 3-х летний ребенок.

# Порядок использования: ./rot13.sh filename
# или                    ./rot13.sh &lt;filename
# или                    ./rot13.sh и ввести текст с клавиатуры (stdin)

cat "$@" | tr 'a-zA-Z' 'n-za-mN-ZA-M'   # "a" заменяется на "n", "b" на "o", и т.д.
#  Конструкция 'cat "$@"'
#+ позволяет вводить данные как со stdin, так и из файла.

exit 0
</pre>
                  </div>

                  <div class="EXAMPLE">
                    <a name="CRYPTOQUOTE"></a>

                    <p><strong>Пример 12-18. Более <span class="QUOTE">"сложный"</span>
                    шифр</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# crypto-quote.sh: Ограниченное шифрование

# Шифрование ограничивается простой заменой одних алфавитных символов другими.
#  Результат очень похож на шифры-загадки


key=ETAOINSHRDLUBCFGJMQPVWZYXK
# Здесь, "key" -- ни что иное, как "перемешанный" алфавит.
# Изменение ключа "key" приведет к изменению шифра.

# Конструкция 'cat "$@"' позволяет вводить данные как со stdin, так и из файла.
# Если используется stdin, то ввод должен завершаться комбинацией Control-D.
# Иначе,  в командной строке, сценарию должно быть передано имя файла.

cat "$@" |  tr "a-z" "A-Z"   | tr "A-Z" "$key"
#        | в верхний регистр |    шифрование
# Такой прием позволяет шифровать как символы в верхнем регистре, так и в нижнем.
# Неалфавитные символы остаются без изменений.


# Попробуйте зашифровать какой либо текст, например
# "Nothing so needs reforming as other people's habits."
# --Mark Twain
#
# Результат будет:
# "CFPHRCS QF CIIOQ MINFMBRCS EQ FPHIM GIFGUI'Q HETRPQ."
# --BEML PZERC

# Для дешифрации можно использовать следующую комбинацию:
# cat "$@" | tr "$key" "A-Z"


#  Этот нехитрый шифр может быть "взломан" 12-ти летним ребенком
#+ с помощью карандаша и бумаги.

exit 0
</pre>
                  </div>

                  <table class="SIDEBAR" border="1" cellpadding="5">
                    <tbody><tr>
                      <td>
                        <div class="SIDEBAR">
                          <a name="AEN7548"></a>

                          <p><strong>Различные версии tr</strong></p>

                          <p>Утилита <strong class="COMMAND">tr</strong> имеет две,
                          исторически сложившиеся, версии. BSD-версия
                          не использует квадратные скобки (<code class="USERINPUT"><strong>tr a-z
                          A-Z</strong></code>), в то время как
                          SysV-версия использует их (<code class="USERINPUT"><strong>tr '[a-z]'
                          '[A-Z]'</strong></code>). GNU-версия
                          утилиты <strong class="COMMAND">tr</strong> напоминает
                          версию BSD, но диапазоны символов обязательно
                          должны заключаться в квадратные скобки.</p>
                        </div>
                      </td>
                    </tr>
                  </tbody></table>
                </dd>

                <dt><a name="FOLDREF"></a><strong class="COMMAND">fold</strong></dt>

                <dd>
                  <p>Выравнивает текст по ширине, разрывая, если это
                  необходимо, слова. Особый интерес представляет ключ
                  <code class="OPTION">-s</code>, который производит перенос
                  строк по пробелам, стараясь не разрывать слова. (см.
                  <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX50">Пример 12-19</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MAILFORMAT">Пример A-2</a>).</p>
                </dd>

                <dt><strong class="COMMAND">fmt</strong></dt>

                <dd>
                  <p>Очень простая утилита форматирования текста, чаще
                  всего используемая как фильтр в конвейерах для того,
                  чтобы выполнить <span class="QUOTE">"перенос"</span> длинных
                  строк текста.</p>

                  <div class="EXAMPLE">
                    <a name="EX50"></a>

                    <p><strong>Пример 12-19. Отформатированный список
                    файлов.</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

WIDTH=40                    # 40 символов в строке.

b=`ls /usr/local/bin`       # Получить список файлов...

echo $b | fmt -w $WIDTH

# То же самое можно выполнить командой
#  echo $b | fold - -s -w $WIDTH
 
exit 0
</pre>
                  </div>

                  <p>См. также <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX41">Пример 12-4</a>.</p>

                  <div class="TIP">
                    <table class="TIP" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/tip.gif" hspace="5" alt="Tip"></td>

                        <td align="left" valign="top">
                          <p>Очень мощной альтернативой утилите <strong class="COMMAND">fmt</strong>, является
                          утилита <strong class="COMMAND">par</strong> (автор Kamil
                          Toman), которую вы сможете найти на <!--noindex--><a href="http://www.cs.berkeley.edu/~amc/Par/" target="_top">http://www.cs.berkeley.edu/~amc/Par/</a><!--/noindex-->.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><strong class="COMMAND">col</strong></dt>

                <dd>
                  <p>Эта утилита с обманчивым названием удаляет из
                  входного потока символы обратной подачи бумаги (код
                  ESC 7). Она так же пытается заменить пробелы на
                  табуляции. Основная область применения утилиты
                  <strong class="COMMAND">col</strong> -- фильтрация вывода
                  отдельных утилит обработки текста, таких как <strong class="COMMAND">groff</strong> и <strong class="COMMAND">tbl</strong>.</p>
                </dd>

                <dt><strong class="COMMAND">column</strong></dt>

                <dd>
                  <p>Форматирование по столбцам. Эта утилита
                  преобразует текст, например какой либо список, в
                  табличное, более <span class="QUOTE">"удобочитаемое"</span>,
                  представление, вставляя символы табуляции по мере
                  необходимости.</p>

                  <div class="EXAMPLE">
                    <a name="COL"></a>

                    <p><strong>Пример 12-20. Пример форматирования
                    списка файлов в каталоге</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# За основу сценария взят пример "man column".


(printf "PERMISSIONS LINKS OWNER GROUP SIZE DATE TIME PROG-NAME\n" \
; ls -l | sed 1d) | column -t

#  Команда "sed 1d" удаляет первую строку, выводимую командой ls,
#+ (для локали "С" это строка:  "total        N",
#+ где "N" -- общее количество файлов.

# Ключ -t, команды "column", означает "табличное" представление.

exit 0
</pre>
                  </div>
                </dd>

                <dt><strong class="COMMAND">colrm</strong></dt>

                <dd>
                  <p>Утилита удаления колонок. Удаляет колонки
                  (столбцы) символов из файла и выводит результат на <code class="FILENAME">stdout</code>. <code class="USERINPUT"><strong>colrm 2 4
                  &lt;filename</strong></code> -- удалит символы со 2-го
                  по 4-й включительно, в каждой строке в файле <code class="FILENAME">filename</code>.</p>

                  <div class="WARNING">
                    <table class="WARNING" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/warning.gif" hspace="5" alt="Warning"></td>

                        <td align="left" valign="top">
                          <p>Если файл содержит символы табуляции или
                          непечатаемые символы, то результат может
                          получиться самым неожиданным. В таких
                          случаях, как правило, утилиту <strong class="COMMAND">colrm</strong>, в конвейере,
                          окружают командами <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXPANDREF">expand</a> и <strong class="COMMAND">unexpand</strong>.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><strong class="COMMAND">nl</strong></dt>

                <dd>
                  <p>Нумерует строки в файле. <code class="USERINPUT"><strong>nl filename</strong></code>
                  -- выведет файл <code class="FILENAME">filename</code> на <code class="FILENAME">stdout</code>, и в начале каждой
                  строки вставит ее порядковый номер, счет начинается с
                  первой непустой строки. Если файл не указывается, то
                  принимается ввод со <code class="FILENAME">stdin.</code></p>

                  <p>Вывод команды <strong class="COMMAND">nl</strong> очень напоминает <code class="USERINPUT"><strong>cat -n</strong></code>,
                  однако, по-умолчанию <strong class="COMMAND">nl</strong> не нумерует пустые
                  строки.</p>

                  <div class="EXAMPLE">
                    <a name="LNUM"></a>

                    <p><strong>Пример 12-21. nl: Самонумерующийся
                    сценарий.</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# Сценарий выводит себя сам на stdout дважды, нумеруя строки сценария.

# 'nl' вставит для этой строки номер 3, поскольку она не нумерует пустые строки.
# 'cat -n' вставит для этой строки номер 5.

nl `basename $0`

echo; echo  # А теперь попробуем вывести текст сценария с помощью 'cat -n'

cat -n `basename $0`
# Различия состоят в том, что 'cat -n' нумерует все строки.
# Обратите внимание: 'nl -ba' -- сделает то же самое.

exit 0
</pre>
                  </div>
                </dd>

                <dt><strong class="COMMAND">pr</strong></dt>

                <dd>
                  <p>Подготовка файла к печати. Утилита производит
                  разбивку файла на страницы, приводя его в вид
                  пригодный для печати или для вывода на экран.
                  Разнообразные ключи позволяют выполнять различные
                  манипуляции над строками и колонками, соединять
                  строки, устанавливать поля, нумеровать строки,
                  добавлять колонтитулы и многое, многое другое.
                  Утилита <strong class="COMMAND">pr</strong> соединяет в себе
                  функциональность таких команд, как <strong class="COMMAND">nl</strong>, <strong class="COMMAND">paste</strong>, <strong class="COMMAND">fold</strong>, <strong class="COMMAND">column</strong> и <strong class="COMMAND">expand</strong>.</p>

                  <p><code class="USERINPUT"><strong>pr -o 5 --width=65 fileZZZ
                  | more</strong></code> -- выдаст хорошо оформленное и
                  разбитое на страницы содержимое файла <code class="FILENAME">fileZZZ</code>.</p>

                  <p>Хочу особо отметить ключ <code class="OPTION">-d</code>, который выводит строки с
                  двойным интервалом (тот же эффект, что и <strong class="COMMAND">sed -G</strong>).</p>
                </dd>

                <dt><a name="GETTEXTREF"></a><strong class="COMMAND">gettext</strong></dt>

                <dd>
                  <p>GNU утилита, предназначена для нужд <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LOCALIZATION">локализации</a> и перевода
                  сообщений программ, выводимых на экран, на язык
                  пользователя. Не смотря на то, что это актуально,
                  прежде всего, для программ на языке C, тем не менее
                  <strong class="COMMAND">gettext</strong> с успехом может
                  использоваться в сценариях командной оболочки для тех
                  же целей. См. <code class="REPLACEABLE"><em>info page</em></code>.</p>
                </dd>

                <dt><strong class="COMMAND">iconv</strong></dt>

                <dd>
                  <p>Утилита преобразования текста из одной кодировки в
                  другую. В основном используется для нужд
                  локализации.</p>
                </dd>

                <dt><strong class="COMMAND">recode</strong></dt>

                <dd>
                  <p>Может рассматриваться как разновилность утилиты
                  <strong class="COMMAND">iconv</strong>, описанной выше.
                  Универсальная утилита для преобразования текстовой
                  информации в различные кодировки.</p>
                </dd>

                <dt><strong class="COMMAND">TeX</strong>, <strong class="COMMAND">gs</strong></dt>

                <dd>
                  <p><strong class="COMMAND">TeX</strong> и <strong class="COMMAND">Postscript</strong> -- языки
                  разметки текста, используемые для подготовки текста к
                  печати или выводу на экран.</p>

                  <p><strong class="COMMAND">TeX</strong> -- это сложная система
                  подготовки к печати, разработанная Дональдом Кнутом
                  (Donald Knuth). Эту утилиту удобнее использовать
                  внутри сценария, чем в командной строке, поскольку в
                  сценарии проще один раз записать все необходимые
                  параметры, передаваемые утилите, для получения
                  необходимого результата.</p>

                  <p><span class="emphasis"><em class="EMPHASIS">Ghostscript</em></span> (<strong class="COMMAND">gs</strong>) -- это GPL-версия
                  интерпретатора Postscript.</p>
                </dd>

                <dt><strong class="COMMAND">groff</strong>, <strong class="COMMAND">tbl</strong>, <strong class="COMMAND">eqn</strong></dt>

                <dd>
                  <p><strong class="COMMAND">groff</strong> -- это еще один язык
                  разметки текста и форматированного вывода. Является
                  расширенной GNU-версией пакета <strong class="COMMAND">roff/troff</strong> в
                  UNIX-системах.</p>

                  <p><strong class="COMMAND">tbl</strong> -- утилита обработки
                  таблиц, должна рассматриваться как составная часть
                  <strong class="COMMAND">groff</strong>, так как ее задачей
                  является преобразование таблиц в команды <strong class="COMMAND">groff</strong>.</p>

                  <p><strong class="COMMAND">eqn</strong> -- утилита
                  преобразования математических выражений в команды
                  <strong class="COMMAND">groff</strong>.</p>
                </dd>

                <dt><strong class="COMMAND">lex</strong>, <strong class="COMMAND">yacc</strong></dt>

                <dd>
                  <p><strong class="COMMAND">lex</strong> -- утилита лексического
                  разбора текста. В Linux-системах заменена на свободно
                  распространяемую утилиту <strong class="COMMAND">flex</strong>.</p>

                  <p><strong class="COMMAND">yacc</strong> -- утилита для
                  создания синтаксических анализаторов, на основе
                  набора грамматик, задаваемых разработчиком. В
                  Linux-системах, эта утилита заменена на свободно
                  распространяемую утилиту <strong class="COMMAND">bison</strong>.</p>
                </dd>
              </dl>
            </div>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="FILEARCHIV"></a>12.5. Команды для работы с файлами и
            архивами</h2>

            <div class="VARIABLELIST">
              <p><strong><a name="FAARCHIVING1"></a>Архивация</strong></p>

              <dl>
                <dt><a name="TARREF"></a><strong class="COMMAND">tar</strong></dt>

                <dd>
                  <p>Стандартная, для UNIX, утилита архивирования.
                  Первоначально -- это была программа <em class="WORDASWORD">Tape ARchiving</em>, которая
                  впоследствии переросла в универсальный пакет, который
                  может работать с любыми типами устройств (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX58">Пример 3-4</a>). В GNU-версию tar была
                  добавлена возможность одновременно производить сжатие
                  tar-архива, например команда <strong class="COMMAND">tar czvf archive_name.tar.gz
                  *</strong> создает tar-архив дерева подкаталогов и
                  вызывает <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GZIPREF">gzip</a> для выполнения сжатия,
                  исключение составляют <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DOTFILESREF">скрытые файлы</a> в текущем
                  каталоге (<strong class="COMMAND">$PWD</strong>). <a name="AEN7816" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN7816"><span class="footnote">[30]</span></a></p>

                  <p>Некоторые, часто используемые, ключи команды
                  <strong class="COMMAND">tar</strong>:</p>

                  <ol type="1">
                    <li>
                      <p><code class="OPTION">-c</code> -- создать (create) новый
                      архив</p>
                    </li>

                    <li>
                      <p><code class="OPTION">-x</code> -- извлечь (extract)
                      файлы из архива</p>
                    </li>

                    <li>
                      <p><code class="OPTION">--delete</code> -- удалить (delete)
                      файлы из архива</p>

                      <div class="CAUTION">
                        <table class="CAUTION" width="90%" border="0">
                          <tbody><tr>
                            <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                            <td align="left" valign="top">
                              <p>Этот ключ игнорируется для накопителей
                              на магнитной ленте.</p>
                            </td>
                          </tr>
                        </tbody></table>
                      </div>
                    </li>

                    <li>
                      <p><code class="OPTION">-r</code> -- добавить (append)
                      файлы в существующий архив</p>
                    </li>

                    <li>
                      <p><code class="OPTION">-A</code> -- добавить (append)
                      <span class="emphasis"><em class="EMPHASIS">tar</em></span>-файлы в
                      существующий архив</p>
                    </li>

                    <li>
                      <p><code class="OPTION">-t</code> -- список файлов в архиве
                      (содержимое архива)</p>
                    </li>

                    <li>
                      <p><code class="OPTION">-u</code> -- обновить (update)
                      архив</p>
                    </li>

                    <li>
                      <p><code class="OPTION">-d</code> -- операция сравнения
                      архива с заданной файловой системой</p>
                    </li>

                    <li>
                      <p><code class="OPTION">-z</code> -- обработка архива с
                      помощью <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GZIPREF">gzip</a></p>

                      <p>(Сжатие или разжатие, в зависимости от
                      комбинации сопутствующих ключей <code class="OPTION">-c</code> или <code class="OPTION">-x</code>)</p>
                    </li>

                    <li>
                      <p><code class="OPTION">-j</code> -- обработка архива с
                      помошью <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BZIPREF">bzip2</a></p>
                    </li>
                  </ol>
                  <br>
                  <br>

                  <div class="CAUTION">
                    <table class="CAUTION" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                        <td align="left" valign="top">
                          <p>При восстановлении "битых" <span class="emphasis"><em class="EMPHASIS">tar.gz</em></span> архивов
                          могут возникнуть определенные сложности,
                          поэтому делайте несколько резервных
                          копий.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><strong class="COMMAND">shar</strong></dt>

                <dd>
                  <p>Утилита создания shell-архива. Архивируемые файлы
                  объединяются в единый файл без выполнения сжатия, в
                  результате получается архив -- по сути полноценный
                  сценарий на языке командной оболочки, начинающийся со
                  строки <span class="TOKEN">#!/bin/sh</span>, который содержит
                  полный набор команд, необходимый для
                  разархивирования. Такого рода архивы до сих пор можно
                  найти в некоторых телеконференциях в Internet, но в
                  последнее время они активно вытесняются связкой
                  <strong class="COMMAND">tar</strong>/<strong class="COMMAND">gzip</strong>. Для распаковки
                  shar-архивов предназначена команда <strong class="COMMAND">unshar</strong>.</p>
                </dd>

                <dt><strong class="COMMAND">ar</strong></dt>

                <dd>
                  <p>Утилита создания и обслуживания архивов, главным
                  образом применяется к двоичным файлам библиотек.</p>
                </dd>

                <dt><a name="RPMREF"></a><strong class="COMMAND">rpm</strong></dt>

                <dd>
                  <p><span class="emphasis"><em class="EMPHASIS">Red Hat Package
                  Manager</em></span>, или <strong class="COMMAND">rpm</strong> -- набор утилит,
                  предназначенных для построения и обслуживания пакетов
                  программного обеспечения как в исходном коде, так и в
                  собранном (откомпилированном) виде. Среди всего
                  прочего, включает в себя утилиты, производящие
                  установку ПО, проверку зависимостей пакетов и
                  проверку их целостности.</p>

                  <p>Самый простой вариант установки ПО из rpm --
                  выполнить команду <strong class="COMMAND">rpm -i
                  package_name.rpm</strong>.</p>

                  <div class="TIP">
                    <table class="TIP" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/tip.gif" hspace="5" alt="Tip"></td>

                        <td align="left" valign="top">
                          <p>Команда <code class="USERINPUT"><strong>rpm
                          -qa</strong></code> выдаст полный список всех
                          установленных <span class="emphasis"><em class="EMPHASIS">rpm</em></span>-пакетов в
                          данной системе. Команда <code class="USERINPUT"><strong>rpm -qa
                          package_name</strong></code> выведет только
                          пакет(ы) с именем, содержащим комбинацию
                          символов <code class="FILENAME">package_name</code>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>rpm -qa</strong></code>
<code class="COMPUTEROUTPUT">redhat-logos-1.1.3-1
 glibc-2.2.4-13
 cracklib-2.7-12
 dosfstools-2.7-1
 gdbm-1.8.0-10
 ksymoops-2.4.1-1
 mktemp-1.5-11
 perl-5.6.0-17
 reiserfs-utils-3.x.0j-2
 ...</code>


<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>rpm -qa docbook-utils</strong></code>
<code class="COMPUTEROUTPUT">docbook-utils-0.6.9-2</code>


<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>rpm -qa docbook | grep docbook</strong></code>
<code class="COMPUTEROUTPUT">docbook-dtd31-sgml-1.0-10
 docbook-style-dsssl-1.64-3
 docbook-dtd30-sgml-1.0-10
 docbook-dtd40-sgml-1.0-11
 docbook-utils-pdf-0.6.9-2
 docbook-dtd41-sgml-1.0-10
 docbook-utils-0.6.9-2</code>
             
</pre>
                          <br>
                          <br>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><strong class="COMMAND">cpio</strong></dt>

                <dd>
                  <p>Специализированная утилита архивации и копирования
                  (<strong class="COMMAND">c</strong>o<strong class="COMMAND">p</strong>y <strong class="COMMAND">i</strong>nput and <strong class="COMMAND">o</strong>utput). Используется все
                  реже и реже, поскольку вытесняется более мощным
                  архиватором <strong class="COMMAND">tar</strong>/<strong class="COMMAND">gzip</strong>. Наиболее
                  употребительна для таких операций, как перемещение
                  дерева каталогов.</p>

                  <div class="EXAMPLE">
                    <a name="EX48"></a>

                    <p><strong>Пример 12-22. Пример перемещения дерева
                    каталогов с помощью cpio</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# Копирование дерева каталогов с помощью cpio.

ARGS=2
E_BADARGS=65

if [ $# -ne "$ARGS" ]
then
  echo "Порядок использования: `basename $0` source destination"
  exit $E_BADARGS
fi

source=$1
destination=$2

find "$source" -depth | cpio -admvp "$destination"
# Информацию по ключам утилиты cpio вы найдете в страницах руководства "man cpio".

exit 0
</pre>
                  </div>
                </dd>

                <dt><strong class="COMMAND">rpm2cpio</strong></dt>

                <dd>
                  <p>Эта утилита конвертирует <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RPMREF">rpm</a>-пакет в архив <strong class="COMMAND">cpio</strong>.</p>

                  <div class="EXAMPLE">
                    <a name="DERPM"></a>

                    <p><strong>Пример 12-23. Распаковка архива <span class="emphasis"><em class="EMPHASIS">rpm</em></span></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# de-rpm.sh: Распаковка архива 'rpm'

: ${1?"Порядок использования: `basename $0` target-file"}
# Сценарию должно быть передано имя архива 'rpm'.


TEMPFILE=$$.cpio                         # Временный файл с "уникальным" именем.
                                         # $$ -- PID процесса сценария.

rpm2cpio &lt; $1 &gt; $TEMPFILE                # Конверсия из rpm в cpio.
cpio --make-directories -F $TEMPFILE -i  # Рапсковка cpio-архива.
rm -f $TEMPFILE                          # Удаление cpio-архива.

exit 0

#  Упражнение:
#  Добавьте проверку на: 1) Существование "target-file"
#+                       2) Действительно ли "target-file" является rpm-архивом.
#  Подсказка:               используйте комсанду 'file'.
</pre>
                  </div>
                </dd>
              </dl>
            </div>

            <div class="VARIABLELIST">
              <p><strong><a name="FACOMPRESSION1"></a>Сжатие</strong></p>

              <dl>
                <dt><a name="GZIPREF"></a><strong class="COMMAND">gzip</strong></dt>

                <dd>
                  <p>Стандартная GNU/UNIX утилита сжатия, заменившая
                  более слабую, и к тому же проприетарную, утилиту
                  <strong class="COMMAND">compress</strong>. Соответствующая
                  утилита декомпрессии (разжатия) -- <strong class="COMMAND">gunzip</strong>, которая является
                  эквивалентом команды <strong class="COMMAND">gzip -d</strong>.</p>

                  <p>Для работы со сжатыми файлами в конвейере
                  используется фильтр <strong class="COMMAND">zcat</strong>, который выводит
                  результат своей работы на <code class="FILENAME">stdout</code>, допускает
                  перенаправление вывода. Фактически это та же команда
                  <strong class="COMMAND">cat</strong>, только приспособленная
                  для работы со сжатыми файлами (включая файлы, сжатые
                  утилитой <strong class="COMMAND">compress</strong>). Эквивалент
                  команды <strong class="COMMAND">zcat</strong> -- <strong class="COMMAND">gzip -dc</strong>.</p>

                  <div class="CAUTION">
                    <table class="CAUTION" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                        <td align="left" valign="top">
                          <p>В некоторых коммерческих версиях UNIX,
                          команда <strong class="COMMAND">zcat</strong> является
                          синонимом команды <strong class="COMMAND">uncompress -c</strong>, и не
                          может работать с файлами, сжатыми с помощью
                          <span class="emphasis"><em class="EMPHASIS">gzip</em></span>.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>

                  <p>См. также <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX14">Пример 7-7</a>.</p>
                </dd>

                <dt><a name="BZIPREF"></a><strong class="COMMAND">bzip2</strong></dt>

                <dd>
                  <p>Альтернативная утилита сжатия, обычно дает более
                  высокую степень сжатия (но при этом работает
                  медленнее), чем <strong class="COMMAND">gzip</strong>, особенно это
                  проявляется на больших файлах. Соответствующая
                  утилита декомпрессии -- <strong class="COMMAND">bunzip2</strong>.</p>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p>В современные версии <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TARREF">tar</a> добавлена поддержка
                          <strong class="COMMAND">bzip2</strong>.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><strong class="COMMAND">compress</strong>, <strong class="COMMAND">uncompress</strong></dt>

                <dd>
                  <p>Устаревшие проприетарные утилиты для работы с
                  архивами, входящие в состав некоторых коммерческих
                  дистрибутивов UNIX. В последнее время вытесняются
                  более мощной утилитой <strong class="COMMAND">gzip</strong>. Linux-дистрибутивы,
                  как правило, включают в свой состав эти утилиты для
                  обратной совместимости, однако <strong class="COMMAND">gunzip</strong> корректно
                  разархивирует файлы, обработанные с помощью <strong class="COMMAND">compress</strong>.</p>

                  <div class="TIP">
                    <table class="TIP" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/tip.gif" hspace="5" alt="Tip"></td>

                        <td align="left" valign="top">
                          <p>Утилита <strong class="COMMAND">znew</strong> предназначена
                          для преобразования <span class="emphasis"><em class="EMPHASIS">compress</em></span>-архивов в
                          <span class="emphasis"><em class="EMPHASIS">gzip</em></span>-архивы.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><strong class="COMMAND">sq</strong></dt>

                <dd>
                  <p>Еще одна утилита-фильтр сжатия, которая
                  обслуживает только отсортированные списки слов.
                  Использует стандартный, для фильтров, синтаксис
                  вызова -- <strong class="COMMAND">sq &lt; input-file &gt;
                  output-file</strong>. Быстрая, но не такая
                  эффективная как <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GZIPREF">gzip</a>. Соответствующая ей утилита
                  декомпрессии называется <strong class="COMMAND">unsq</strong>, синтаксис вызова
                  аналогичен утилите <strong class="COMMAND">sq</strong>.</p>

                  <div class="TIP">
                    <table class="TIP" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/tip.gif" hspace="5" alt="Tip"></td>

                        <td align="left" valign="top">
                          <p>Вывод от <strong class="COMMAND">sq</strong> может быть
                          передан по конвейеру утилите <strong class="COMMAND">gzip</strong>, для
                          дальнейшего сжатия.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><strong class="COMMAND">zip</strong>, <strong class="COMMAND">unzip</strong></dt>

                <dd>
                  <p>Кроссплатформенная утилита архивирования и сжатия,
                  совместимая, по формату архивного файла, с утилитой
                  DOS -- <span class="emphasis"><em class="EMPHASIS">pkzip.exe</em></span>. <span class="QUOTE">"Zip"</span>-архивы,
                  по-моему, более приемлемый вариант для обмена данными
                  через Internet, чем <span class="QUOTE">"tarballs"</span> (тарболлы,
                  или tar-архивы).</p>
                </dd>

                <dt><strong class="COMMAND">unarc</strong>, <strong class="COMMAND">unarj</strong>, <strong class="COMMAND">unrar</strong></dt>

                <dd>
                  <p>Этот набор утилит предназначен для распаковки
                  архивов, созданных с помощью DOS архиваторов -- <span class="emphasis"><em class="EMPHASIS">arc.exe</em></span>, <span class="emphasis"><em class="EMPHASIS">arj.exe</em></span> и <span class="emphasis"><em class="EMPHASIS">rar.exe</em></span>.</p>
                </dd>
              </dl>
            </div>

            <div class="VARIABLELIST">
              <p><strong><a name="FAINFORMATION1"></a>Получение сведений о
              файлах</strong></p>

              <dl>
                <dt><a name="FILEREF"></a><strong class="COMMAND">file</strong></dt>

                <dd>
                  <p>Утилита идентификации файлов. Команда <code class="USERINPUT"><strong>file
                  file-name</strong></code> верне тип файла <code class="FILENAME">file-name</code>, например, <code class="COMPUTEROUTPUT">ascii text</code> или <code class="COMPUTEROUTPUT">data</code>. Для этого она
                  анализирует сигнатуру, или <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MAGNUMREF">магическое число</a> и
                  сопоставляет ее со списком известных сигнатур из <code class="FILENAME">/usr/share/magic</code>, <code class="FILENAME">/etc/magic</code> или <code class="FILENAME">/usr/lib/magic</code> (в зависимости
                  от дистрибутива Linux/UNIX).</p>

                  <p><code class="OPTION">-f</code> -- ключ пакетного режима
                  работы утилиты <strong class="COMMAND">file</strong>, в этом случае утилита
                  принимает список анализируемых имен файлов из
                  заданного файла. Ключ <code class="OPTION">-z</code> используется для анализа
                  файлов в архиве.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>file test.tar.gz</strong></code>
<code class="COMPUTEROUTPUT">test.tar.gz: gzip compressed data, deflated, last modified: Sun Sep 16 13:34:51 2001, os: Unix</code>

<code class="PROMPT">bash</code> <code class="USERINPUT"><strong>file -z test.tar.gz</strong></code>
<code class="COMPUTEROUTPUT">test.tar.gz: GNU tar archive (gzip compressed data, deflated, last modified: Sun Sep 16 13:34:51 2001, os: Unix)</code>
             
</pre>
                  <br>
                  <br>

                  <div class="EXAMPLE">
                    <a name="STRIPC"></a>

                    <p><strong>Пример 12-24. Удаление комментариев из
                    файла с текстом программы на языке C</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# strip-comment.sh: Удаление комментариев (/* COMMENT */) из исходных текстов программ на языке C.

E_NOARGS=65
E_ARGERROR=66
E_WRONG_FILE_TYPE=67

if [ $# -eq "$E_NOARGS" ]
then
  echo "Порядок использования: `basename $0` C-program-file" &gt;&amp;2 # Вывод сообщения на stderr.
  exit $E_ARGERROR
fi

# Проверка типа файла.
type=`eval file $1 | awk '{ print $2, $3, $4, $5 }'`
# "file $1" -- выводит тип файла...
# затем awk удаляет первое поле -- имя файла...
# после этого результат записывается в переменную "type".
correct_type="ASCII C program text"

if [ "$type" != "$correct_type" ]
then
  echo
  echo "Этот сценарий работает только с исходными текстами программ на языке C."
  echo
  exit $E_WRONG_FILE_TYPE
fi


# Довольно замысловатый сценарий sed :
#--------
sed '
/^\/\*/d
/.*\/\*/d
' $1
#--------
# Если вы потратите несколько часов на изучение основ sed, то он станет немного понятнее.


#  Следовало бы добавить еще обработку
#+ комментариев, расположенных в одной строке с кодом.
#  Оставляю это вам, в качестве упражнения.

# Кроме того, этот сценарий удалит все строки, которые содержат комбинации символов "*/" или "/*",
# не всегда желаемый результат.

exit 0


# ----------------------------------------------------------------
# Строки, расположенные ниже не будут исполнены из-за стоящей выше команды 'exit 0'.

# Stephane Chazelas предложил другой, альтернативный вариант:

usage() {
  echo "Порядок использования: `basename $0` C-program-file" &gt;&amp;2
  exit 1
}

WEIRD=`echo -n -e '\377'`   # или WEIRD=$'\377'
[[ $# -eq 1 ]] || usage
case `file "$1"` in
  *"C program text"*) sed -e "s%/\*%${WEIRD}%g;s%\*/%${WEIRD}%g" "$1" \
     | tr '\377\n' '\n\377' \
     | sed -ne 'p;n' \
     | tr -d '\n' | tr '\377' '\n';;
  *) usage;;
esac

# Этот вариант, все еще некорректно обрабатывает такие строки как:
# printf("/*");
# или
# /*  /* ошибочный вложенный комментарий */
#
# Для обработки специальных случаев (\", \\" ...) придется написать синтаксический анализатор
# (может быть с помощью lex или yacc?).

exit 0
</pre>
                  </div>
                </dd>

                <dt><a name="WHIC"></a><strong class="COMMAND">which</strong></dt>

                <dd>
                  <p>Команда <strong class="COMMAND">which command-xxx</strong> вернет
                  полный путь к <span class="QUOTE">"command-xxx"</span>. Очень
                  полезна для того, чтобы узнать -- установлена ли та
                  или иная утилита в системе.</p>

                  <p><code class="USERINPUT"><strong>$bash which
                  rm</strong></code></p>
<pre class="SCREEN"><code class="COMPUTEROUTPUT">/usr/bin/rm</code>
</pre>
                  <br>
                  <br>
                </dd>

                <dt><strong class="COMMAND">whereis</strong></dt>

                <dd>
                  <p>Очень похожа на <strong class="COMMAND">which</strong>, упоминавшуюся выше.
                  Команда <strong class="COMMAND">whereis command-xxx</strong> вернет
                  полный путь к <span class="QUOTE">"command-xxx"</span>, но
                  кроме того, еще и путь к <span class="emphasis"><em class="EMPHASIS">manpage</em></span> -- файлу,
                  странице справочника по заданной утилите.</p>

                  <p><code class="USERINPUT"><strong>$bash whereis
                  rm</strong></code></p>
<pre class="SCREEN"><code class="COMPUTEROUTPUT">rm: /bin/rm /usr/share/man/man1/rm.1.bz2</code>
</pre>
                  <br>
                  <br>
                </dd>

                <dt><a name="WHATISREF"></a><strong class="COMMAND">whatis</strong></dt>

                <dd>
                  <p>Утилита <strong class="COMMAND">whatis filexxx</strong> отыщет <span class="QUOTE">"filexxx"</span> в своей
                  базе данных. Может рассматриваться как упрощенный
                  вариант команды <strong class="COMMAND">man</strong>.</p>

                  <p><code class="USERINPUT"><strong>$bash whatis
                  whatis</strong></code></p>
<pre class="SCREEN"><code class="COMPUTEROUTPUT">whatis               (1)  - search the whatis database for complete words</code>
</pre>
                  <br>
                  <br>

                  <div class="EXAMPLE">
                    <a name="WHAT"></a>

                    <p><strong>Пример 12-25. Исследование каталога <code class="FILENAME">/usr/X11R6/bin</code></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# Что находится в каталоге /usr/X11R6/bin?

DIRECTORY="/usr/X11R6/bin"
# Попробуйте также "/bin", "/usr/bin", "/usr/local/bin", и т.д.

for file in $DIRECTORY/*
do
  whatis `basename $file`   # Вывод информации о файле.
done

exit 0
# Вывод этого сценария можно перенаправить в файл:
# ./what.sh &gt;&gt;whatis.db
# или включить постраничный просмотр на экране,
# ./what.sh | less
</pre>
                  </div>

                  <p>См. также <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FILEINFO">Пример 10-3</a>.</p>
                </dd>

                <dt><strong class="COMMAND">vdir</strong></dt>

                <dd>
                  <p>Вывод списка файлов в каталоге. Тот же эффект
                  имеет команда <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LSREF">ls -l</a>.</p>

                  <p>Это одна из утилит GNU <span class="emphasis"><em class="EMPHASIS">fileutils</em></span>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>vdir</strong></code>
<code class="COMPUTEROUTPUT">total 10
 -rw-r--r--    1 bozo  bozo      4034 Jul 18 22:04 data1.xrolo
 -rw-r--r--    1 bozo  bozo      4602 May 25 13:58 data1.xrolo.bak
 -rw-r--r--    1 bozo  bozo       877 Dec 17  2000 employment.xrolo</code>

<code class="PROMPT">bash</code> <code class="USERINPUT"><strong>ls -l</strong></code>
<code class="COMPUTEROUTPUT">total 10
 -rw-r--r--    1 bozo  bozo      4034 Jul 18 22:04 data1.xrolo
 -rw-r--r--    1 bozo  bozo      4602 May 25 13:58 data1.xrolo.bak
 -rw-r--r--    1 bozo  bozo       877 Dec 17  2000 employment.xrolo</code>
             
</pre>
                  <br>
                  <br>
                </dd>

                <dt><strong class="COMMAND">locate</strong>, <strong class="COMMAND">slocate</strong></dt>

                <dd>
                  <p>Команда <strong class="COMMAND">locate</strong> определяет
                  местонахождение файла, используя свою базу данных,
                  создаваемую специально для этих целей. Команда
                  <strong class="COMMAND">slocate</strong> -- это защищенная
                  версия <strong class="COMMAND">locate</strong> (которая может
                  оказаться простым псевдонимом команды <strong class="COMMAND">slocate</strong>).</p>

                  <p><code class="USERINPUT"><strong>$bash locate
                  hickson</strong></code></p>
<pre class="SCREEN"><code class="COMPUTEROUTPUT">/usr/lib/xephem/catalogs/hickson.edb</code>
</pre>
                  <br>
                  <br>
                </dd>

                <dt><strong class="COMMAND">readlink</strong></dt>

                <dd>
                  <p>Возвращает имя файла, на который указывает
                  символическая ссылка.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>readlink /usr/bin/awk</strong></code>
<code class="COMPUTEROUTPUT">../../bin/gawk</code>
             
</pre>
                  <br>
                  <br>
                </dd>

                <dt><strong class="COMMAND">strings</strong></dt>

                <dd>
                  <p>Команда <strong class="COMMAND">strings</strong> используется для
                  поиска печатаемых строк в двоичных файлах. Она
                  выводит последовательности печатаемых символов,
                  обнаруженных в заданном файле. Может использоваться
                  для прикидочного анализа дамп-файлов (core dump) или
                  для отыскания информации о типе файла, например для
                  графических файлов неизвестного формата (например,
                  <code class="USERINPUT"><strong>strings image-file |
                  more</strong></code> может вывести такую строчку: <code class="COMPUTEROUTPUT">JFIF</code>, что говорит о том,
                  что мы имеем дело с графическим файлом в формате
                  <span class="emphasis"><em class="EMPHASIS">jpeg</em></span>). В сценариях,
                  вероятнее всего, вам придется использовать эту
                  команду в связке с <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GREPREF">grep</a> или <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SEDREF">sed</a>. См. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BINGREP">Пример 10-7</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FINDSTRING">Пример 10-9</a>.</p>

                  <div class="EXAMPLE">
                    <a name="WSTRINGS"></a>

                    <p><strong>Пример 12-26. <span class="QUOTE">"Расширенная"</span>
                    команда <span class="emphasis"><em class="EMPHASIS">strings</em></span></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# wstrings.sh: "word-strings" (расширенная команда "strings")
#
#  Этот сценарий фильтрует вывод команды "strings" путем проверки на соответствие
#+ выводимых слов по файлу словаря.
#  Таким способом эффективно "отсекается" весь "мусор",
#+ и выводятся только распознанные слова.

# =================================================================
#                 Стандартная проверка входных аргументов
ARGS=1
E_BADARGS=65
E_NOFILE=66

if [ $# -ne $ARGS ]
then
  echo "Порядок использования: `basename $0` filename"
  exit $E_BADARGS
fi

if [ ! -f "$1" ]                      # Проверка наличия файла.
then
    echo "Файл \"$1\" не найден."
    exit $E_NOFILE
fi
# =================================================================


MINSTRLEN=3                           #  Минимальная длина строки.
WORDFILE=/usr/share/dict/linux.words  #  Файл словаря.
                                      #  Можно указать иной
                                      #+ файл словаря
                                      #+ в формате -- "одно слово на строке".


wlist=`strings "$1" | tr A-Z a-z | tr '[:space:]' Z | \
tr -cs '[:alpha:]' Z | tr -s '\173-\377' Z | tr Z ' '`

# Трансляция вывода от 'strings' с помощью нескольких 'tr'.
#  "tr A-Z a-z"  -- перевод в нижний регистр.
#  "tr '[:space:]'"  -- конвертирует пробелы в символы Z.
#  "tr -cs '[:alpha:]' Z"  -- конвертирует неалфавитные символы в символы Z,
#+ и удаляет повторяющиеся символы Z.
#  "tr -s '\173-\377' Z"  -- Конвертирует все символы, с кодами выше 'z' в Z
#+ и удаляет повторяющиеся символы Z,
#+ эта команда удалит все символы, которые не были распознаны предыдущими
#+ командами трансляции (tr).
#  Наконец, "tr Z ' '" -- преобразует все символы Z в пробелы,
#+ которые будут рассматриваться в качестве разделителя слов в цикле, приведенном ниже.

#  Обратите внимание на технику многоуровневой обработки с помощью 'tr',
#+ каждый раз эта команда вызывается с различным набором аргументов.


for word in $wlist                    # Важно:
                                      # переменная $wlist не должна заключаться в кавычки.
                                      # "$wlist" -- не сработает.
                                      # Почему?
do

  strlen=${#word}                     # Дина строки.
  if [ "$strlen" -lt "$MINSTRLEN" ]   # Не рассматривать короткие строки.
  then
    continue
  fi

  grep -Fw $word "$WORDFILE"          # Проверка слова по словарю.

done


exit 0
</pre>
                  </div>
                </dd>
              </dl>
            </div>

            <div class="VARIABLELIST">
              <p><strong><a name="COMPARISONN1"></a>Сравнение</strong></p>

              <dl>
                <dt><a name="DIFFREF"></a><strong class="COMMAND">diff</strong>, <strong class="COMMAND">patch</strong></dt>

                <dd>
                  <p><strong class="COMMAND">diff</strong>: очень гибкая утилита
                  сравнения файлов. Она выполняет построчное сравнение
                  файлов. В отдельных случаях, таких как поиск по
                  словарю, может оказаться полезной фильтрация файлов с
                  помощью <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SORTREF">sort</a> и <strong class="COMMAND">uniq</strong> перед тем как отдать
                  поток данных через конвейер утилите <strong class="COMMAND">diff</strong>. <code class="USERINPUT"><strong>diff file-1
                  file-2</strong></code> -- выведет строки, имеющие
                  отличия, указывая -- какому файлу, какая строка
                  принадлежит.</p>

                  <p>С ключом <code class="OPTION">--side-by-side</code>, команда <strong class="COMMAND">diff</strong> выведет сравниваемые
                  файлы в две колонки, с указанием несовпадающих строк.
                  Ключи <code class="OPTION">-c</code> и <code class="OPTION">-u</code> так же служат для облегчения
                  интерпретации результатов работы <strong class="COMMAND">diff</strong>.</p>

                  <p>Существует ряд интерфейсных оболочек для утилиты
                  <strong class="COMMAND">diff</strong>, среди них можно
                  назвать: <strong class="COMMAND">spiff</strong>, <strong class="COMMAND">wdiff</strong>, <strong class="COMMAND">xdiff</strong> и <strong class="COMMAND">mgdiff</strong>.</p>

                  <div class="TIP">
                    <table class="TIP" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/tip.gif" hspace="5" alt="Tip"></td>

                        <td align="left" valign="top">
                          <p>Команда <strong class="COMMAND">diff</strong> возвращает код
                          завершения 0, если сравниваемые файлы
                          идентичны и 1, если они отличаются. Это
                          позволяет использовать <strong class="COMMAND">diff</strong> в условных
                          операторах внутри сценариев на языке
                          командной оболочки (см. ниже).</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>

                  <p>В общем случае, <strong class="COMMAND">diff</strong> используется для
                  генерации файла различий, который используется как
                  аргумент команды <strong class="COMMAND">patch</strong>. Ключ <code class="OPTION">-e</code> отвечает за вывод файла
                  различий в формате, пригодном для использования с
                  <strong class="COMMAND">ed</strong> или <strong class="COMMAND">ex</strong>.</p>

                  <p><strong class="COMMAND">patch</strong>: гибкая утилита для
                  "наложения заплат". С помощью файла
                  различий, сгенерированного утилитой <strong class="COMMAND">diff</strong>, утилита <strong class="COMMAND">patch</strong> может использоваться
                  для обновления устаревших версий файлов. Это
                  позволяет распространять относительно небольшие <span class="QUOTE">"diff"</span>-файлы вместо
                  целых пакетов. Распространение <span class="QUOTE">"заплат"</span> к ядру стало
                  наиболее предпочтительным методом распространения
                  более новых версий ядра Linux.</p>
<pre class="PROGRAMLISTING">patch -p1 &lt;patch-file
# Применит все изменения из 'patch-file'
# к файлам, описанным там же.
# Так выполняется обновление пакетов до более высоких версий.
</pre>
                  <br>
                  <br>

                  <p>Наложение "заплат" на ядро:</p>
<pre class="PROGRAMLISTING">cd /usr/src
gzip -cd patchXX.gz | patch -p0
# Обновление исходных текстов ядра с помощью 'patch'.
# Пример взят из файла "README",
# автор не известен (Alan Cox?).
</pre>
                  <br>
                  <br>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p>Кроме того, утилита <strong class="COMMAND">diff</strong> в состоянии
                          выполнять рекурсивный обход каталогов.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>diff -r ~/notes1 ~/notes2</strong></code>
<code class="COMPUTEROUTPUT">Only in /home/bozo/notes1: file02
 Only in /home/bozo/notes1: file03
 Only in /home/bozo/notes2: file04</code>
             
</pre>
                          <br>
                          <br>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>

                  <div class="TIP">
                    <table class="TIP" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/tip.gif" hspace="5" alt="Tip"></td>

                        <td align="left" valign="top">
                          <p>Утилита <strong class="COMMAND">zdiff</strong> сравнивает
                          сжатые, с помощью <span class="emphasis"><em class="EMPHASIS">gzip</em></span>,
                          файлы.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><strong class="COMMAND">diff3</strong></dt>

                <dd>
                  <p>Расширенная версия <strong class="COMMAND">diff</strong>, которая сравнивает
                  сразу 3 файла. В случае успеха возвращает 0, но, к
                  сожалению, не дает никакой информации о результатах
                  сравнения.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>diff3 file-1 file-2 file-3</strong></code>
<code class="COMPUTEROUTPUT">====
 1:1c
   This is line 1 of "file-1".
 2:1c
   This is line 1 of "file-2".
 3:1c
   This is line 1 of "file-3"</code>
             
</pre>
                  <br>
                  <br>
                </dd>

                <dt><strong class="COMMAND">sdiff</strong></dt>

                <dd>
                  <p>Сравнение и/или редактирование двух файлов перед
                  объединением их в один файл. Это интерактивная
                  утилита, по своей природе, и из-за этого она довольно
                  редко используется в сценариях.</p>
                </dd>

                <dt><strong class="COMMAND">cmp</strong></dt>

                <dd>
                  <p>Утилита <strong class="COMMAND">cmp</strong> -- это упрощенная
                  версия <strong class="COMMAND">diff</strong>. В то время, как
                  <strong class="COMMAND">diff</strong> выводит подробную
                  информацию об имеющихся различиях, утилита <strong class="COMMAND">cmp</strong> лишь показывет номер
                  строки и позицию в строке, где было встречено
                  различие.</p>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p>Подобно команде <strong class="COMMAND">diff</strong>, команда
                          <strong class="COMMAND">cmp</strong> возвращает код
                          завершения 0, если файлы идентичны и 1, если
                          они различны. Это позволяет использовать
                          команду <strong class="COMMAND">cmp</strong> в условных
                          операторах.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>

                  <div class="EXAMPLE">
                    <a name="FILECOMP"></a>

                    <p><strong>Пример 12-27. Пример сравнения двух
                    файлов с помощью cmp.</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

ARGS=2  # Ожидаются два аргумента командной строки.
E_BADARGS=65
E_UNREADABLE=66

if [ $# -ne "$ARGS" ]
then
  echo "Порядок использования: `basename $0` file1 file2"
  exit $E_BADARGS
fi

if [[ ! -r "$1" || ! -r "$2" ]]
then
  echo "Оба файла должны существовать и должны быть доступны для чтения."
  exit $E_UNREADABLE
fi

cmp $1 $2 &amp;&gt; /dev/null  # /dev/null -- "похоронит" вывод от команды "cmp".
#   cmp -s $1 $2  даст тот же результат ("-s" -- флаг "тишины" для "cmp")
#   Спасибо Anders Gustavsson за замечание.
#
# Также применимо к 'diff', т.е.,   diff $1 $2 &amp;&gt; /dev/null

if [ $? -eq 0 ]         # Проверка кода возврата команды "cmp".
then
  echo "Файл \"$1\" идентичен файлу \"$2\"."
else
  echo "Файл \"$1\" отличается от файла \"$2\"."
fi

exit 0
</pre>
                  </div>

                  <div class="TIP">
                    <table class="TIP" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/tip.gif" hspace="5" alt="Tip"></td>

                        <td align="left" valign="top">
                          <p>Для работы с <span class="emphasis"><em class="EMPHASIS">gzip</em></span> файлами
                          используется утилита <strong class="COMMAND">zcmp</strong>.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><strong class="COMMAND">comm</strong></dt>

                <dd>
                  <p>Универсальная утилита сравнения. Работает с
                  отсортированными файлами.</p>

                  <p><strong class="COMMAND">comm <code class="REPLACEABLE"><em>-options</em></code> <code class="REPLACEABLE"><em>first-file</em></code> <code class="REPLACEABLE"><em>second-file</em></code></strong></p>

                  <p><code class="USERINPUT"><strong>comm file-1
                  file-2</strong></code> -- вывод в три колонки:</p>

                  <ul>
                    <li>
                      <p>колонка 1 = уникальные строки для <code class="FILENAME">file-1</code></p>
                    </li>

                    <li>
                      <p>колонка 2 = уникальные строки для <code class="FILENAME">file-2</code></p>
                    </li>

                    <li>
                      <p>колонка 3 = одинаковые строки.</p>
                    </li>
                  </ul>
                  <br>
                  <br>

                  <p>Ключи, подавляющие вывод в одной или более
                  колонках.</p>

                  <ul>
                    <li>
                      <p><code class="OPTION">-1</code> -- подавление вывода в
                      колонку <code class="LITERAL">1</code></p>
                    </li>

                    <li>
                      <p><code class="OPTION">-2</code> -- подавление вывода в
                      колонку <code class="LITERAL">2</code></p>
                    </li>

                    <li>
                      <p><code class="OPTION">-3</code> -- подавление вывода в
                      колонку <code class="LITERAL">3</code></p>
                    </li>

                    <li>
                      <p><code class="OPTION">-12</code> -- подавление вывода в
                      колонки <code class="LITERAL">1</code> и <code class="LITERAL">2</code>, и т.д.</p>
                    </li>
                  </ul>
                  <br>
                  <br>
                </dd>
              </dl>
            </div>

            <div class="VARIABLELIST">
              <p><strong><a name="FAUTILS1"></a>Утилиты</strong></p>

              <dl>
                <dt><strong class="COMMAND">basename</strong></dt>

                <dd>
                  <p>Выводит только название файла, без каталога
                  размещения. Конструкция <code class="USERINPUT"><strong>basename $0</strong></code>
                  -- позволяет сценарию узнать свое имя, то есть имя
                  файла, который был запущен. Это имя может быть
                  использовано для вывода сообщений, напрмиер:</p>
<pre class="PROGRAMLISTING">echo "Порядок использования: `basename $0` arg1 arg2 ... argn"
</pre>
                  <br>
                  <br>
                </dd>

                <dt><strong class="COMMAND">dirname</strong></dt>

                <dd>
                  <p>Отсекает <strong class="COMMAND">basename</strong> от полного имени
                  файла и выводит только путь к файлу.</p>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p>Утилитам <strong class="COMMAND">basename</strong> и <strong class="COMMAND">dirname</strong> может быть
                          передана любая строка, в качестве аргумента.
                          Этот аргумент необязательно должен быть
                          именем существующего файла (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DAYSBETWEEN">Пример A-8</a>).</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>

                  <div class="EXAMPLE">
                    <a name="EX35"></a>

                    <p><strong>Пример 12-28. Утилиты basename и
                    dirname</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

a=/home/bozo/daily-journal.txt

echo "Basename для /home/bozo/daily-journal.txt = `basename $a`"
echo "Dirname для /home/bozo/daily-journal.txt = `dirname $a`"
echo
echo "Мой домашний каталог `basename ~/`."             # Можно указать просто ~.
echo "Каталог моего домашнего каталога `dirname ~/`."  # Можно указать просто ~.

exit 0
</pre>
                  </div>
                </dd>

                <dt><strong class="COMMAND">split</strong></dt>

                <dd>
                  <p>Утилита разбивает файл на несколько частей. Обычно
                  используется для разбиения больших файлов, чтобы их
                  можно было записать на дискеты или передать по
                  электронной почте по частям.</p>
                </dd>

                <dt><strong class="COMMAND">sum</strong>, <strong class="COMMAND">cksum</strong>, <a name="MD5SUMREF"></a><strong class="COMMAND">md5sum</strong></dt>

                <dd>
                  <p>Эти утилиты предназначены для вычисления
                  контрольных сумм. Контрольная сумма -- это некоторое
                  число, вычисляемое исходя из содержимого файла, и
                  служит для контроля целостности информации в файле.
                  Сценарий может выполнять проверку контрольных сумм
                  для того, чтобы убедиться, что файл не был изменен
                  или поврежден. Для большей безопасности,
                  рекомендуется использовать 128-битную сумму,
                  генерируемую утилитой <strong class="COMMAND">md5sum</strong> (<strong class="COMMAND">m</strong>essage <strong class="COMMAND">d</strong>igest check<strong class="COMMAND">sum</strong>).</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>cksum /boot/vmlinuz</strong></code>
<code class="COMPUTEROUTPUT">1670054224 804083 /boot/vmlinuz</code>


<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>md5sum /boot/vmlinuz</strong></code>
<code class="COMPUTEROUTPUT">0f43eccea8f09e0a0b2b5cf1dcf333ba  /boot/vmlinuz</code>
             
</pre>
                  <br>
                  <br>

                  <p>Обратите внимание: утилита <strong class="COMMAND">cksum</strong> выводит контрольную
                  сумму и размер файла в байтах.</p>

                  <div class="EXAMPLE">
                    <a name="FILEINTEGRITY"></a>

                    <p><strong>Пример 12-29. Проверка целостности
                    файла</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# file-integrity.sh: Проверка целостности файлов в заданном каталоге

E_DIR_NOMATCH=70
E_BAD_DBFILE=71

dbfile=File_record.md5
# Файл для хранения контрольных сумм.


set_up_database ()
{
  echo ""$directory"" &gt; "$dbfile"
  # Записать название каталога в первую строку файла.
  md5sum "$directory"/* &gt;&gt; "$dbfile"
  # Записать контрольные суммы md5 и имена файлов.
}

check_database ()
{
  local n=0
  local filename
  local checksum

  # ------------------------------------------- #
  #  Возможно эта проверка и не нужна,
  #+ но лучше перестраховаться сейчас, чем жалеть об этом потом.

  if [ ! -r "$dbfile" ]
  then
    echo "Не могу прочитать файл с контрольными суммами!"
    exit $E_BAD_DBFILE
  fi
  # ------------------------------------------- #

  while read record[n]
  do

    directory_checked="${record[0]}"
    if [ "$directory_checked" != "$directory" ]
    then
      echo "Имя каталога не совпадает с записаным в файле!"
      # Попытка использовать файл контрольных сумм для другого каталога.
      exit $E_DIR_NOMATCH
    fi

    if [ "$n" -gt 0 ]   # Не имя каталога.
    then
      filename[n]=$( echo ${record[$n]} | awk '{ print $2 }' )
      #  md5sum записывает в обратном порядке,
      #+ сначала контрольную сумму, затем имя файла.
      checksum[n]=$( md5sum "${filename[n]}" )

      if [ "${record[n]}" = "${checksum[n]}" ]
      then
        echo "Файл ${filename[n]} не был изменен."
      else
        echo "ОШИБКА КОНТРОЛЬНОЙ СУММЫ для файла ${filename[n]}!"
        # Файл был изменен со времени последней проверки.
      fi

    fi


    let "n+=1"
  done &lt;"$dbfile"       # Чтение контрольных сумм из файла.

}

# =================================================== #
# main ()

if [ -z  "$1" ]
then
  directory="$PWD"      #  Если каталог не задан,
else                    #+ то используется текущий каталог.
  directory="$1"
fi

clear                   # Очистка экрана.

# ------------------------------------------------------------------ #
  if [ ! -r "$dbfile" ] # Необходимо создать файл с контрольными суммами?
  then
    echo "Создание файла с контрольными суммами, \""$directory"/"$dbfile"\"."; echo
    set_up_database
  fi
# ------------------------------------------------------------------ #

check_database          # Выполнить проверку.

echo

#  Вывод этого сценария можно перенаправить в файл,
#+ это особенно полезно при проверке большого количества файлов.

#  Более строгая проверка целостности файлов,
#+ может быть выполнена с помощью пакета "Tripwire",
#+ http://sourceforge.net/projects/tripwire/.

exit 0
</pre>
                  </div>

                  <p>Более творческий подход к использованию <strong class="COMMAND">md5sum</strong> вы нйдете в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DIRECTORYINFO">Пример A-21</a>.</p>
                </dd>

                <dt><a name="SHREDREF"></a><strong class="COMMAND">shred</strong></dt>

                <dd>
                  <p>Надежное, с точки зрения безопасности, стирание
                  файла, посредством предварительной, многократной
                  записи в файл случайной информации, перед тем как
                  удалить его. Эта команда имеет тот же эффект, что и
                  <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BLOTOUT">Пример 12-42</a>, но делает это
                  более изящным и безопасным способом.</p>

                  <p>Является составной частью пакета GNU <span class="emphasis"><em class="EMPHASIS">fileutils</em></span>.</p>

                  <div class="CAUTION">
                    <table class="CAUTION" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                        <td align="left" valign="top">
                          <p>Имеется ряд технологий, с помощью которых
                          все-таки возможно восстановить файлы,
                          удаленные утилитой <strong class="COMMAND">shred</strong>.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>
              </dl>
            </div>

            <div class="VARIABLELIST">
              <p><strong><a name="FAENCENCR1"></a>Кодирование и
              шифрование</strong></p>

              <dl>
                <dt><strong class="COMMAND">uuencode</strong></dt>

                <dd>
                  <p>Эта утилита используется для кодирования двоичных
                  файлов в символы ASCII, после такого кодирования
                  файлы могут, с достаточной степенью безопасности,
                  передаваться по сети, вкладываться в электронные
                  письма и т.п..</p>
                </dd>

                <dt><strong class="COMMAND">uudecode</strong></dt>

                <dd>
                  <p>Утилита декодирования файлов, прошедших обработку
                  утилитой uuencode.</p>

                  <div class="EXAMPLE">
                    <a name="EX52"></a>

                    <p><strong>Пример 12-30. Декодирование
                    файлов</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

lines=35        # 35 строк для заголовка (более чем достаточно).

for File in *   # Обход всех файлов в текущем каталоге...
do
  search1=`head -$lines $File | grep begin | wc -w`
  search2=`tail -$lines $File | grep end | wc -w`
  #  Закодированные файлы начинаются со слова "begin",
  #+ и заканчиваются словом "end".
  if [ "$search1" -gt 0 ]
  then
    if [ "$search2" -gt 0 ]
    then
      echo "декодируется файл - $File -"
      uudecode $File
    fi
  fi
done

#  Обратите внимание: если передать сценарию самого себя, для декодирования,
#+ то это введет его в заблуждение
#+ поскольку в тексте сценария встречаются слова "begin" и "end".

exit 0
</pre>
                  </div>

                  <div class="TIP">
                    <table class="TIP" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/tip.gif" hspace="5" alt="Tip"></td>

                        <td align="left" valign="top">
                          <p>При декодировании и выводе длинных
                          текстовых сообщений из новостных групп
                          Usenet, очень нелишним будет передать текст,
                          по конвейеру, команде <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FOLDREF">fold -s</a>.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><strong class="COMMAND">mimencode</strong>, <strong class="COMMAND">mmencode</strong></dt>

                <dd>
                  <p>Утилиты <strong class="COMMAND">mimencode</strong> и <strong class="COMMAND">mmencode</strong> предназначены для
                  обработки закодированных мультимедийных вложений в
                  электронные письма. Хотя <span class="emphasis"><em class="EMPHASIS">почтовые программы</em></span>
                  (такие как <strong class="COMMAND">pine</strong> или <strong class="COMMAND">kmail</strong>) имеют возможность
                  автоматической обработки таких вложений, тем не менее
                  эти утилиты позволяют обрабатывать вложения вручную,
                  из командной строки или в пакетном режиме, из
                  сценария на языке командной оболочки.</p>
                </dd>

                <dt><strong class="COMMAND">crypt</strong></dt>

                <dd>
                  <p>Одно время, это была стандартная, для UNIX,
                  утилита шифрования файлов. <a name="AEN8616" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN8616"><span class="footnote">[31]</span></a> Политически
                  мотивированные, правительственные постановления ряда
                  стран, напрямую запрещают экспорт программного
                  обеспечения для шифрования, что, в результате,
                  привело практически к полному исчезновению <strong class="COMMAND">crypt</strong> из большинства
                  UNIX-систем (в том числе и Linux). К счастью,
                  программистами было разработано множество вполне
                  приличных альтернатив, и среди них <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html" "ftp:="" metalab.unc.edu="" pub="" linux="" utils="" file="" cruft-0.2.tar.gz"="" target="_top">cruft</a> (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ENCRYPTEDPW">Пример A-5</a>).</p>
                </dd>
              </dl>
            </div>

            <div class="VARIABLELIST">
              <p><strong><a name="FAMISC1"></a>Прочее</strong></p>

              <dl>
                <dt><a name="MKTEMPREF"></a><strong class="COMMAND">mktemp</strong></dt>

                <dd>
                  <p>Создает временный файл с <span class="QUOTE">"уникальным"</span>
                  именем.</p>
<pre class="PROGRAMLISTING">PREFIX=filename
tempfile=`mktemp $PREFIX.XXXXXX`
#                        ^^^^^^ Необходимо по меньшей мере 6 заполнителей
echo "имя временного файла = $tempfile"
# имя временного файла = filename.QA2ZpY
#                 или нечто подобное...
</pre>
                  <br>
                  <br>
                </dd>

                <dt><strong class="COMMAND">make</strong></dt>

                <dd>
                  <p>Утилита для компиляции и сборки программ. Но может
                  использоваться для выполнения любых других операций,
                  основанных на анализе наличия изменений в исходных
                  файлах.</p>

                  <p><a name="MAKEFILEREF"></a></p>

                  <p>Команда <strong class="COMMAND">make</strong> использует в своей
                  работе <code class="FILENAME">Makefile</code>, который содержит
                  перечень зависимостей и операций, которые необходимо
                  выполнить для удовлетворения этих зависимостей.</p>
                </dd>

                <dt><strong class="COMMAND">install</strong></dt>

                <dd>
                  <p>Своего рода -- утилита копирования файлов, похожа
                  на <strong class="COMMAND">cp</strong>, но дополнительно
                  позволяет изменять права доступа и атрибуты
                  копируемых файлов. Напрямую эта команда практически
                  не используется, чаще всего она встречается в <code class="FILENAME">Makefile</code> (в разделе <code class="REPLACEABLE"><em>make install :</em></code>).
                  Она может использоваться в сценариях установки
                  ПО.</p>
                </dd>

                <dt><strong class="COMMAND">dos2unix</strong></dt>

                <dd>
                  <p>Автор утилиты -- Benjamin Lin со-товарищи.
                  Предназначена для преобразования текстовых файлов из
                  формата DOS (в котором строки завершаются комбинацией
                  символов CR-LF) в формат UNIX (в котором строки
                  завершаются одним символом LF) и обратно.</p>
                </dd>

                <dt><strong class="COMMAND">ptx</strong></dt>

                <dd>
                  <p>Команда <strong class="COMMAND">ptx [targetfile]</strong> выводит a
                  упорядоченный предметный указатель для targetfile,
                  который можно обработать, по мере необходимости,
                  какой либо утилитой форматирования, в конвейере.</p>
                </dd>

                <dt><strong class="COMMAND">more</strong>, <strong class="COMMAND">less</strong></dt>

                <dd>
                  <p>Команды постраничного просмотра текстовых файлов
                  или потоков на <code class="FILENAME">stdout</code>. Могут использоваться в
                  сценариях в качестве фильтров.</p>
                </dd>
              </dl>
            </div>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="COMMUNICATIONS"></a>12.6. Команды для работы с
            сетью</h2>

            <p>Команды, описываемые в этом разделе, могут найти
            применение при исследовании и анализе процессов передачи
            данных по сети, а также могут использоваться в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CSPAMMERS">борьбе со спамерами</a>.</p>

            <div class="VARIABLELIST">
              <p><strong><a name="COMMUNINFO1"></a>Информация и
              статистика</strong></p>

              <dl>
                <dt><strong class="COMMAND">host</strong></dt>

                <dd>
                  <p>Возвращает информацию об узле Интернета, по
                  заданному имени или IP адресу, выполняя поиск с
                  помощью службы DNS.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>host surfacemail.com</strong></code>
<code class="COMPUTEROUTPUT">surfacemail.com. has address 202.92.42.236</code>
             
</pre>
                  <br>
                  <br>
                </dd>

                <dt><strong class="COMMAND">ipcalc</strong></dt>

                <dd>
                  <p>Производит поиск IP адреса. С ключом <code class="OPTION">-h</code>, <strong class="COMMAND">ipcalc</strong> выполняет поиск
                  имени хоста в DNS, по заданному IP адресу.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>ipcalc -h 202.92.42.236</strong></code>
<code class="COMPUTEROUTPUT">HOSTNAME=surfacemail.com</code>
             
</pre>
                  <br>
                  <br>
                </dd>

                <dt><strong class="COMMAND">nslookup</strong></dt>

                <dd>
                  <p>Выполняет <span class="QUOTE">"поиск имени узла"</span>
                  Интернета по заданному IP адресу. По сути,
                  эквивалентна командам <strong class="COMMAND">ipcalc -h</strong> и <strong class="COMMAND">dig -x</strong>. Команда может
                  исполняться как в интерактивном, так и в
                  неинтерактивном режиме, т.е. в пределах сценария.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>nslookup -sil 66.97.104.180</strong></code>
<code class="COMPUTEROUTPUT">nslookup kuhleersparnis.ch
 Server:         135.116.137.2
 Address:        135.116.137.2#53

 Non-authoritative answer:
 Name:   kuhleersparnis.ch</code>
             
</pre>
                  <br>
                  <br>
                </dd>

                <dt><strong class="COMMAND">dig</strong></dt>

                <dd>
                  <p>Подобно команде <strong class="COMMAND">nslookup</strong>, выполняет <span class="QUOTE">"поиск имени узла"</span> в
                  Интернете.</p>

                  <p>Сравните вывод команды <strong class="COMMAND">dig -x</strong> с выводом команд
                  <strong class="COMMAND">ipcalc -h</strong> и <strong class="COMMAND">nslookup</strong>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>dig -x 81.9.6.2</strong></code>
<code class="COMPUTEROUTPUT">;; Got answer:
 ;; -&gt;&gt;HEADER&lt;&lt;- opcode: QUERY, status: NXDOMAIN, id: 11649
 ;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0

 ;; QUESTION SECTION:
 ;2.6.9.81.in-addr.arpa.         IN      PTR

 ;; AUTHORITY SECTION:
 6.9.81.in-addr.arpa.    3600    IN      SOA     ns.eltel.net. noc.eltel.net.
 2002031705 900 600 86400 3600

 ;; Query time: 537 msec
 ;; SERVER: 135.116.137.2#53(135.116.137.2)
 ;; WHEN: Wed Jun 26 08:35:24 2002
 ;; MSG SIZE  rcvd: 91</code>
             
</pre>
                  <br>
                  <br>
                </dd>

                <dt><strong class="COMMAND">traceroute</strong></dt>

                <dd>
                  <p>Утилита предназначена для исследования топологии
                  сети посредством передачи ICMP пакетов удаленному
                  узлу. Эта программа может работать в LAN, WAN и в
                  Интернет. Удаленный узел может быть указан как по
                  имени, так и по IP адресу. Вывод команды traceroute
                  может быть передан по конвейеру утилитам <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GREPREF">grep</a> или <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SEDREF">sed</a>, для дальнейшего анализа.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>traceroute 81.9.6.2</strong></code>
<code class="COMPUTEROUTPUT">traceroute to 81.9.6.2 (81.9.6.2), 30 hops max, 38 byte packets
 1  tc43.xjbnnbrb.com (136.30.178.8)  191.303 ms  179.400 ms  179.767 ms
 2  or0.xjbnnbrb.com (136.30.178.1)  179.536 ms  179.534 ms  169.685 ms
 3  192.168.11.101 (192.168.11.101)  189.471 ms  189.556 ms *
 ...</code>
             
</pre>
                  <br>
                  <br>
                </dd>

                <dt><strong class="COMMAND">ping</strong></dt>

                <dd>
                  <p>Выполняет передачу пакета <span class="QUOTE">"ICMP ECHO_REQUEST"</span>
                  другой системе в сети. Чаще всего служит в качестве
                  инструмента диагностики соединений, должна
                  использоваться с большой осторожностью.</p>

                  <p>В случае успеха, <strong class="COMMAND">ping</strong> возвращает <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXITSTATUSREF">код завершения</a> <span class="ERRORCODE">0</span>, поэтому команда ping
                  может использоваться в условных операторах.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>ping localhost</strong></code>
<code class="COMPUTEROUTPUT">PING localhost.localdomain (127.0.0.1) from 127.0.0.1 : 56(84) bytes of data.
 Warning: time of day goes back, taking countermeasures.
 64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=0 ttl=255 time=709 usec
 64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=1 ttl=255 time=286 usec

 --- localhost.localdomain ping statistics ---
 2 packets transmitted, 2 packets received, 0% packet loss
 round-trip min/avg/max/mdev = 0.286/0.497/0.709/0.212 ms</code>
             
</pre>
                  <br>
                  <br>
                </dd>

                <dt><a name="WHOISREF"></a><strong class="COMMAND">whois</strong></dt>

                <dd>
                  <p>Выполняет поиск в DNS (Domain Name System). Ключом
                  <code class="OPTION">-h</code> можно указать какой из <span class="emphasis"><em class="EMPHASIS">whois</em></span> серверов будет
                  запрошен. См. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX18">Пример 4-6</a>.</p>
                </dd>

                <dt><strong class="COMMAND">finger</strong></dt>

                <dd>
                  <p>Возвращает информацию о пользователях в сети. По
                  желанию, эта команда может выводить содержимое файлов
                  <code class="FILENAME">~/.plan</code>, <code class="FILENAME">~/.project</code> и <code class="FILENAME">~/.forward</code>, указанного
                  пользователя.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>finger</strong></code>
<code class="COMPUTEROUTPUT">Login  Name           Tty      Idle  Login Time   Office     Office Phone
 bozo   Bozo Bozeman   tty1        8  Jun 25 16:59
 bozo   Bozo Bozeman   ttyp0          Jun 25 16:59
 bozo   Bozo Bozeman   ttyp1          Jun 25 17:07</code>



<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>finger bozo</strong></code>
<code class="COMPUTEROUTPUT">Login: bozo                             Name: Bozo Bozeman
 Directory: /home/bozo                   Shell: /bin/bash
 On since Fri Aug 31 20:13 (MST) on tty1    1 hour 38 minutes idle
 On since Fri Aug 31 20:13 (MST) on pts/0   12 seconds idle
 On since Fri Aug 31 20:13 (MST) on pts/1
 On since Fri Aug 31 20:31 (MST) on pts/2   1 hour 16 minutes idle
 No mail.
 No Plan.</code>
             
</pre>
                  <br>
                  <br>

                  <p>По соображениям безопасности, в большинстве сетей
                  служба <strong class="COMMAND">finger</strong>, и соответствующий
                  демон, отключена. <a name="AEN8859" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN8859"><span class="footnote">[32]</span></a></p>
                </dd>

                <dt><strong class="COMMAND">vrfy</strong></dt>

                <dd>
                  <p>Проверка адреса электронной почты.</p>
                </dd>
              </dl>
            </div>

            <div class="VARIABLELIST">
              <p><strong><a name="COMMREMOTE1"></a>Доступ к удаленным
              системам</strong></p>

              <dl>
                <dt><strong class="COMMAND">sx</strong>, <strong class="COMMAND">rx</strong></dt>

                <dd>
                  <p>Команды <strong class="COMMAND">sx</strong> и <strong class="COMMAND">rx</strong> служат для
                  приема/передачи файлов на/из удаленный узел в сети,
                  по протоколу <span class="emphasis"><em class="EMPHASIS">xmodem</em></span>. Входят в состав
                  пакета <strong class="COMMAND">minicom</strong>.</p>
                </dd>

                <dt><strong class="COMMAND">sz</strong>, <strong class="COMMAND">rz</strong></dt>

                <dd>
                  <p>Команды <strong class="COMMAND">sz</strong> и <strong class="COMMAND">rz</strong> служат для
                  приема/передачи файлов на/из удаленный узел в сети,
                  по протоколу <span class="emphasis"><em class="EMPHASIS">zmodem</em></span>. Протокол <span class="emphasis"><em class="EMPHASIS">zmodem</em></span> имеет некоторые
                  преимущества перед протоколом <span class="emphasis"><em class="EMPHASIS">xmodem</em></span>, в качестве
                  такого преимущества можно назвать более высокую
                  скорость передачи и возможность возобновления
                  передачи, в случае ее разрыва. Входят в состав пакета
                  <strong class="COMMAND">minicom</strong>.</p>
                </dd>

                <dt><a name="FTPREF"></a><strong class="COMMAND">ftp</strong></dt>

                <dd>
                  <p>Под этим именем подразумевается утилита и протокол
                  передачи файлов. Сеансы ftp могут устанавливаться из
                  сценариев (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX72">Пример 17-7</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ENCRYPTEDPW">Пример A-5</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTPGET">Пример A-14</a>).</p>
                </dd>

                <dt><strong class="COMMAND">uucp</strong></dt>

                <dd>
                  <p><span class="emphasis"><em class="EMPHASIS">UNIX to UNIX copy</em></span>. Это
                  коммуникационный пакет для передачи файлов между UNIX
                  серверами. Сценарий на языке командной оболочки --
                  один из самых эффективных способов автоматизации
                  такого обмена.</p>

                  <p>Похоже, что с появлением Интернет и электронной
                  почты, <strong class="COMMAND">uucp</strong> постепенно уходит в
                  небытие, однако, она с успехом может использоваться в
                  изолированных, не имеющих выхода в Интернет,
                  сетях.</p>
                </dd>

                <dt><strong class="COMMAND">cu</strong></dt>

                <dd>
                  <p><span class="emphasis"><em class="EMPHASIS">C</em></span>all <span class="emphasis"><em class="EMPHASIS">U</em></span>p -- выполняет
                  соединение с удаленной системой, как простой
                  терминал. Эта команда является частью пакета <strong class="COMMAND">uucp</strong> и, своего рода,
                  упрощенным вариантом команды <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TELNETREF">telnet</a>.</p>
                </dd>

                <dt><a name="TELNETREF"></a><strong class="COMMAND">telnet</strong></dt>

                <dd>
                  <p>Утилита и протокол для подключения к удаленной
                  системе.</p>

                  <div class="CAUTION">
                    <table class="CAUTION" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                        <td align="left" valign="top">
                          <p>Протокол telnet небезопасен по своей
                          природе, поэтому следует воздерживаться от
                          его использования.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><strong class="COMMAND">wget</strong></dt>

                <dd>
                  <p><strong class="COMMAND">wget</strong> -- <span class="emphasis"><em class="EMPHASIS">неинтерактивная</em></span> утилита
                  для скачивания файлов с Web или ftp сайтов.</p>
<pre class="PROGRAMLISTING">wget -p http://www.xyz23.com/file01.html
wget -r ftp://ftp.xyz24.net/~bozo/project_files/ -o $SAVEFILE
</pre>
                  <br>
                  <br>
                </dd>

                <dt><strong class="COMMAND">lynx</strong></dt>

                <dd>
                  <p><strong class="COMMAND">lynx</strong> -- Web браузер, внутри
                  сценариев (с ключом <code class="OPTION">-dump</code>) может использоваться для
                  скачивания файлов с Web или ftp сайтов, в
                  неинтерактивном режиме.</p>
<pre class="PROGRAMLISTING">lynx -dump http://www.xyz23.com/file01.html &gt;$SAVEFILE
</pre>
                  <br>
                  <br>
                </dd>

                <dt><strong class="COMMAND">rlogin</strong></dt>

                <dd>
                  <p><code class="REPLACEABLE"><em>Remote login</em></code> --
                  инициирует сессию с удаленной системой. Эта команда
                  небезопасна, вместо нее лучше использовать <code>ssh</code>.</p>
                </dd>

                <dt><strong class="COMMAND">rsh</strong></dt>

                <dd>
                  <p><code class="REPLACEABLE"><em>Remote shell</em></code> --
                  исполняет команду на удаленной системе. Эта команда
                  небезопасна, вместо нее лучше использовать <code>ssh</code>.</p>
                </dd>

                <dt><strong class="COMMAND">rcp</strong></dt>

                <dd>
                  <p><code class="REPLACEABLE"><em>Remote copy</em></code> --
                  копирование файлов между двумя машинами через сеть.
                  Подобно прочим r* утилитам, команда <strong class="COMMAND">rcp</strong> небезопасна и потому,
                  использовать ее в сценариях нежелательно. В качестве
                  замены можно порекомендовать <strong class="COMMAND">ssh</strong> или <strong class="COMMAND">expect</strong>.</p>
                </dd>

                <dt><a name="SS"></a><strong class="COMMAND">ssh</strong></dt>

                <dd>
                  <p><code class="REPLACEABLE"><em>Secure shell</em></code> --
                  устанавливает сеанс связи и выполняет команды на
                  удаленной системе. Выступает в качестве защищенной
                  замены для <strong class="COMMAND">telnet</strong>, <strong class="COMMAND">rlogin</strong>, <strong class="COMMAND">rcp</strong> и <strong class="COMMAND">rsh</strong>. Использует
                  идентификацию, аутентификацию и шифрование
                  информации, передаваемой через сеть. Подробности вы
                  найдете в <span class="emphasis"><em class="EMPHASIS">man ssh</em></span>.</p>
                </dd>
              </dl>
            </div>

            <div class="VARIABLELIST">
              <p><strong><a name="COMMLOCAL1"></a>Локальная сеть</strong></p>

              <dl>
                <dt><a name="WRITEREF"></a><strong class="COMMAND">write</strong></dt>

                <dd>
                  <p>Эта утилита позволяет передать текст сообщения на
                  другой терминал (console или xterm). Разрешить или
                  запретить доступ к терминалу можно с помощью команды
                  <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MESGREF">mesg</a>.</p>

                  <p>Поскольку команда <strong class="COMMAND">write</strong> работает в
                  интерактивном режиме, то, как правило, она не
                  употребляется в сценариях.</p>
                </dd>
              </dl>
            </div>

            <div class="VARIABLELIST">
              <p><strong><a name="COMMMAIL1"></a>Mail</strong></p>

              <dl>
                <dt><strong class="COMMAND">mail</strong></dt>

                <dd>
                  <p>Чтение или передача электронной почты.</p>

                  <p>Этот почтовый клиент командной строки с успехом
                  может использоваться в сценариях.</p>

                  <div class="EXAMPLE">
                    <a name="SELFMAILER"></a>

                    <p><strong>Пример 12-31. Сценарий, отправляющий
                    себя самого по электронной почте</strong></p>
<pre class="PROGRAMLISTING">#!/bin/sh
# self-mailer.sh: Сценарий отправляет себя самого по электронной почте

adr=${1:-`whoami`}     # Если пользователь не указан, то -- себе самому.
#  Вызов 'self-mailer.sh wiseguy@superdupergenius.com'
#+ приведет к передаче электронного письма по указанному адресу.
#  Вызов 'self-mailer.sh' (без аргументов) -- отправит письмо
#+ пользователю, запустившему сценарий, например, bozo@localhost.localdomain.
#
#  Дополнительно о конструкции ${parameter:-default},
#+ см. раздел "Подстановка параметров"
#+ в главе "К вопросу о переменных".

# ============================================================================
  cat $0 | mail -s "Сценарий \"`basename $0`\" отправил себя сам." "$adr"
# ============================================================================

# --------------------------------------------
#  Поздравляю!
#  Этот сценарий запустила какая-то "редиска",
#+ и заставила отправить этот текст к Вам.
#  Очевидно кто-то не знает
#+ куда девать свое время.
# --------------------------------------------

echo "`date`, сценарий \"`basename $0`\" отправлен "$adr"."

exit 0
</pre>
                  </div>
                </dd>

                <dt><strong class="COMMAND">mailto</strong></dt>

                <dd>
                  <p>Команда <strong class="COMMAND">mailto</strong>, похожа на <strong class="COMMAND">mail</strong>, она также отправляет
                  сообщения по электронной почте. Однако, кроме этого,
                  <strong class="COMMAND">mailto</strong> позволяет отправлять
                  MIME (multimedia) сообщения.</p>
                </dd>

                <dt><strong class="COMMAND">vacation</strong></dt>

                <dd>
                  <p>Эта утилита предназначена для автоматической
                  передачи ответов на электронные письма, например для
                  того, чтобы уведомить отправителя о том, что
                  получатель временно отсутствует. Работает совместно с
                  <strong class="COMMAND">sendmail</strong> и не может
                  использоваться для передачи сообщений через
                  коммутируемые линии (по модему).</p>
                </dd>
              </dl>
            </div>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="TERMINALCCMDS"></a>12.7. Команды управления
            терминалом</h2>

            <div class="VARIABLELIST">
              <p><strong><a name="TERMCOMMANDLISTING1"></a>Команды, имеющие
              отношение к консоли или терминалу</strong></p>

              <dl>
                <dt><strong class="COMMAND">tput</strong></dt>

                <dd>
                  <p>инициализация терминала или выполнение запроса к
                  базе данных терминалов <code class="FILENAME">terminfo</code>. С помощью <strong class="COMMAND">tput</strong> можно выполнять
                  различные операции. <strong class="COMMAND">tput clear</strong> -- эквивалентно
                  команде <strong class="COMMAND">clear</strong>. <strong class="COMMAND">tput reset</strong> -- эквивалентно
                  команде <strong class="COMMAND">reset</strong>. <strong class="COMMAND">tput sgr0</strong> -- так же
                  сбрасывет настройки терминал, но без очистки
                  экрана.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>tput longname</strong></code>
<code class="COMPUTEROUTPUT">xterm terminal emulator (XFree86 4.0 Window System)</code>
             
</pre>
                  <br>
                  <br>

                  <p>Команда <strong class="COMMAND">tput cup X Y</strong> перемещает
                  курсор в координаты (X,Y). Обычно этой команде
                  предшествует <strong class="COMMAND">clear</strong>, очищающая экран.</p>

                  <p>Обратите внимание: <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#STTYREF">stty</a> предлагает более широкий
                  диапазон возможностей.</p>
                </dd>

                <dt><strong class="COMMAND">infocmp</strong></dt>

                <dd>
                  <p>Cравнение или печать информации о характеристиках
                  терминалов, хранящейся в базе данных <span class="emphasis"><em class="EMPHASIS">terminfo</em></span>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>infocmp</strong></code>
<code class="COMPUTEROUTPUT">#       Reconstructed via infocmp from file:
 /usr/share/terminfo/r/rxvt
 rxvt|rxvt terminal emulator (X Window System),
         am, bce, eo, km, mir, msgr, xenl, xon,
         colors#8, cols#80, it#8, lines#24, pairs#64,
         acsc=``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
         bel=^G, blink=\E[5m, bold=\E[1m,
         civis=\E[?25l,
         clear=\E[H\E[2J, cnorm=\E[?25h, cr=^M,
         ...</code>
             
</pre>
                  <br>
                  <br>
                </dd>

                <dt><strong class="COMMAND">reset</strong></dt>

                <dd>
                  <p>Сбрасывает настройки терминала и очищает экран.
                  Как и в случае команды <strong class="COMMAND">clear</strong>, курсор и приглашение
                  к вводу (prompt) выводятся в верхнем левом углу
                  терминала.</p>
                </dd>

                <dt><a name="CLEARREF"></a><strong class="COMMAND">clear</strong></dt>

                <dd>
                  <p>Команда <strong class="COMMAND">clear</strong> просто очищает экран
                  терминала или окно xterm. Курсор и приглашение к
                  вводу (prompt) выводятся в верхнем левом углу
                  терминала. Эта команда может запускаться как из
                  командной строки, так и из сценария. См. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX30">Пример 10-25</a>.</p>
                </dd>

                <dt><strong class="COMMAND">script</strong></dt>

                <dd>
                  <p>Эта утилита позволяет сохранять в файле все
                  символы, введенные пользователем c клавиатуры (вывод
                  тоже). Получая, фактически, подробнейший синхронный
                  протокол сессии.</p>
                </dd>
              </dl>
            </div>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="MATHC"></a>12.8. Команды выполнения математических
            операций</h2>

            <div class="VARIABLELIST">
              <p><strong><a name="MATHCOMMANDLISTING1"></a></strong></p>

              <dl>
                <dt><strong class="COMMAND">factor</strong></dt>

                <dd>
                  <p>Разложение целого числа на простые множители.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>factor 27417</strong></code>
<code class="COMPUTEROUTPUT">27417: 3 13 19 37</code>
             
</pre>
                  <br>
                  <br>
                </dd>

                <dt><a name="BCREF"></a><strong class="COMMAND">bc</strong></dt>

                <dd>
                  <p>Bash не в состоянии выполнять действия над числами
                  с плавающей запятой и не содержит многих важных
                  математических функций. К счастью существует <strong class="COMMAND">bc</strong>.</p>

                  <p>Универсальная, выполняющая вычисления с
                  произвольной точностью, утилита <strong class="COMMAND">bc</strong> обладает некоторыми
                  возможностями, характерными для языков
                  программирования.</p>

                  <p>Синтаксис <strong class="COMMAND">bc</strong> немного напоминает язык
                  C.</p>

                  <p>Поскольку это утилита UNIX, то она может
                  достаточно широко использоваться в сценариях на языке
                  командной оболочки, в том числе и в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PIPEREF">конвейерной</a> обработке
                  данных.</p>

                  <p>Ниже приводится простой шаблон работы с утилитой
                  <strong class="COMMAND">bc</strong> в сценарии. Здесь
                  используется прием <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COMMANDSUBREF">подстановки команд</a>.</p>
<pre class="SCREEN">             <code class="USERINPUT"><strong>variable=$(echo "OPTIONS; OPERATIONS" | bc)</strong></code>
             
</pre>
                  <br>
                  <br>

                  <div class="EXAMPLE">
                    <a name="MONTHLYPMT"></a>

                    <p><strong>Пример 12-32. Ежемесячные выплаты по
                    займу</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# monthlypmt.sh: Расчет ежемесячных выплат по займу.


#  Это измененный вариант пакета "mcalc" (mortgage calculator),
#+ написанного Jeff Schmidt и Mendel Cooper (ваш покорный слуга).
#   http://www.ibiblio.org/pub/Linux/apps/financial/mcalc-1.6.tar.gz  [15k]

echo
echo "Введите сумму займа, процентную ставку и срок займа,"
echo "для расчета суммы ежемесячных выплат."

bottom=1.0

echo
echo -n "Сумма займа (без запятых -- с точностью до доллара) "
read principal
echo -n "Процентная ставка (процент) "  # Если 12%, то нужно вводить "12", а не ".12".
read interest_r
echo -n "Срок займа (месяцев) "
read term


 interest_r=$(echo "scale=9; $interest_r/100.0" | bc) # Здесь "scale" -- точность вычислений.


 interest_rate=$(echo "scale=9; $interest_r/12 + 1.0" | bc)


 top=$(echo "scale=9; $principal*$interest_rate^$term" | bc)

 echo; echo "Прошу подождать. Вычисления потребуют некоторого времени."

 let "months = $term - 1"
# ====================================================================
 for ((x=$months; x &gt; 0; x--))
 do
   bot=$(echo "scale=9; $interest_rate^$x" | bc)
   bottom=$(echo "scale=9; $bottom+$bot" | bc)
#  bottom = $(($bottom + $bot"))
 done
# --------------------------------------------------------------------
#  Rick Boivie предложил более эффективную реализацию
#+ цикла вычислений, который дает выигрыш по времени на 2/3.

# for ((x=1; x &lt;= $months; x++))
# do
#   bottom=$(echo "scale=9; $bottom * $interest_rate + 1" | bc)
# done


#  А затем нашел еще более эффективную альтернативу,
#+ которая выполняется в 20 раз быстрее !!!

# bottom=`{
#     echo "scale=9; bottom=$bottom; interest_rate=$interest_rate"
#     for ((x=1; x &lt;= $months; x++))
#     do
#          echo 'bottom = bottom * interest_rate + 1'
#     done
#     echo 'bottom'
#     } | bc`       # Внедрить цикл 'for' в конструкцию подстановки команд.

# ====================================================================

 # let "payment = $top/$bottom"
 payment=$(echo "scale=2; $top/$bottom" | bc)
 # Два знака после запятой, чтобы показать доллары и центы.

 echo
 echo "ежемесячные выплаты = \$$payment"  # Вывести знак "доллара" перед числом.
 echo


 exit 0

 # Упражнения:
 #   1) Добавьте возможность ввода суммы с точностью до цента.
 #   2) Добавьте возможность ввода процентной ставки как в виде процентов, так и в виде десятичного числа -- доли целого.
 #   3) Если вы действительно честолюбивы,
 #      добавьте в сценарий вывод полной таблицы помесячных выплат.
</pre>
                  </div>

                  <div class="EXAMPLE">
                    <a name="BASE"></a>

                    <p><strong>Пример 12-33. Перевод чисел из одной
                    системы счисления в другую</strong></p>
<pre class="PROGRAMLISTING">:
##########################################################################
# Shellscript:  base.sh - вывод чисел в разных системах счисления (Bourne Shell)
# Author     :  Heiner Steven (heiner.steven@odn.de)
# Date       :  07-03-95
# Category   :  Desktop
# $Id: base.sh,v 1.2 2000/02/06 19:55:35 heiner Exp $
##########################################################################
# Description
#
# Changes
# 21-03-95 stv  исправлена ошибка, возникающая при вводе числа 0xb (0.2)
##########################################################################

# ==&gt; Используется в данном документе с разрешения автора.
# ==&gt; Комментарии добавлены автором документа.

NOARGS=65
PN=`basename "$0"`                             # Имя программы
VER=`echo '$Revision: 1.2 $' | cut -d' ' -f2`  # ==&gt; VER=1.2

Usage () {
    echo "$PN - вывод чисел в различных системах счисления, $VER (stv '95)
Порядок использования: $PN [number ...]

Если число не задано, то производится ввод со stdin.
Число может быть:
    двоичное            должно начинаться с комбинации символов 0b (например 0b1100)
    восьмеричное        должно начинаться с 0  (например 014)
    шестнадцатиричное   должно начинаться с комбинации символов 0x (например 0xc)
    десятичное          в любом другом случае (например 12)" &gt;&amp;2
    exit $NOARGS
}   # ==&gt; Функция вывода сообщения о порядке использования.

Msg () {
    for i   # ==&gt; [список] параметров опущен.
    do echo "$PN: $i" &gt;&amp;2
    done
}

Fatal () { Msg "$@"; exit 66; }

PrintBases () {
    # Определение системы счисления
    for i      # ==&gt; [список] параметров опущен...
    do         # ==&gt; поэтому работает с аргументами командной строки.
        case "$i" in
            0b*)                ibase=2;;       # двоичная
            0x*|[a-f]*|[A-F]*)  ibase=16;;      # шестнадцатиричная
            0*)                 ibase=8;;       # восьмеричная
            [1-9]*)             ibase=10;;      # десятичная
            *)
                Msg "Ошибка в числе $i - число проигнорировано"
                continue;;
        esac

        # Удалить префикс и преобразовать шестнадцатиричные цифры в верхний регистр (этого требует bc)
        number=`echo "$i" | sed -e 's:^0[bBxX]::' | tr '[a-f]' '[A-F]'`
        # ==&gt; вместо "/", здесь используется символ ":" как разделитель для sed.

        # Преобразование в десятичную систему счисления
        dec=`echo "ibase=$ibase; $number" | bc`  # ==&gt; 'bc' используется как калькулятор.
        case "$dec" in
            [0-9]*)     ;;       # все в порядке
            *)          continue;; # ошибка: игнорировать
        esac

        # Напечатать все преобразования в одну строку.
        # ==&gt; 'вложенный документ' -- список команд для 'bc'.
        echo `bc &lt;&lt;!
            obase=16; "hex="; $dec
            obase=10; "dec="; $dec
            obase=8;  "oct="; $dec
            obase=2;  "bin="; $dec
!
    ` | sed -e 's: :    :g'

    done
}

while [ $# -gt 0 ]
do
    case "$1" in
        --)     shift; break;;
        -h)     Usage;;          # ==&gt; Вывод справочного сообщения.
        -*)     Usage;;
        *)      break;;          # первое число
    esac   # ==&gt; Хорошо бы расширить анализ вводимых символов.
    shift
done

if [ $# -gt 0 ]
then
    PrintBases "$@"
else                                    # чтение со stdin
    while read line
    do
        PrintBases $line
    done
fi
</pre>
                  </div>

                  <p>Один из вариантов вызова <strong class="COMMAND">bc</strong> -- использование <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#HEREDOCREF">вложенного документа</a>,
                  внедряемого в блок с <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COMMANDSUBREF">подстановкой команд</a>. Это
                  особенно актуально, когда сценарий должен передать
                  <strong class="COMMAND">bc</strong> значительный по объему
                  список команд и аргументов.</p>
<pre class="PROGRAMLISTING">variable=`bc &lt;&lt; LIMIT_STRING
options
statements
operations
LIMIT_STRING
`
</pre>
                  ...или... 
<pre class="PROGRAMLISTING">variable=$(bc &lt;&lt; LIMIT_STRING
options
statements
operations
LIMIT_STRING
)
</pre>
                  <br>
                  <br>

                  <div class="EXAMPLE">
                    <a name="ALTBC"></a>

                    <p><strong>Пример 12-34. Пример взаимодействия bc
                    со <span class="QUOTE">"встроенным
                    документом"</span></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Комбинирование 'bc' с
# 'вложенным документом'.


var1=`bc &lt;&lt; EOF
18.33 * 19.78
EOF
`
echo $var1       # 362.56


#  запись $( ... ) тоже работает.
v1=23.53
v2=17.881
v3=83.501
v4=171.63

var2=$(bc &lt;&lt; EOF
scale = 4
a = ( $v1 + $v2 )
b = ( $v3 * $v4 )
a * b + 15.35
EOF
)
echo $var2       # 593487.8452


var3=$(bc -l &lt;&lt; EOF
scale = 9
s ( 1.7 )
EOF
)
# Возвращается значение синуса от 1.7 радиана.
# Ключом "-l" вызывается математическая библиотека 'bc'.
echo $var3       # .991664810


# Попробуем функции...
hyp=             # Объявление глобальной переменной.
hypotenuse ()    # Расчет гипотенузы прямоугольного треугольника.
{
hyp=$(bc -l &lt;&lt; EOF
scale = 9
sqrt ( $1 * $1 + $2 * $2 )
EOF
)
# К сожалению, функции Bash не могут возвращать числа с плавающей запятой.
}

hypotenuse 3.68 7.31
echo "гипотенуза = $hyp"    # 8.184039344


exit 0
</pre>
                  </div>

                  <div class="EXAMPLE">
                    <a name="CANNON"></a>

                    <p><strong>Пример 12-35. Вычисление числа
                    "пи"</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# cannon.sh: Аппроксимация числа "пи".

# Это очень простой вариант реализации метода "Monte Carlo",
#+ математическое моделирование событий реальной жизни,
#+ для эмуляции случайного события используются псевдослучайные числа.

#  Допустим, что мы располагаем картой квадратного участка поверхности со стороной квадрата 10000 единиц.
#  На этом участке, в центре, находится совершенно круглое озеро,
#+ с диаметром в 10000 единиц.
#  Т.е. озеро покрывает почти всю карту, кроме ее углов.
#  (Фактически -- это квадрат со вписанным кругом.)
#
#  Пусть по этому участку ведется стрельба железными ядрами из древней пушки
#  Все ядра падают где-то в пределах данного участка,
#+ т.е. либо в озеро, либо на сушу, по углам участка.
#  Поскольку озеро покрывает большую часть участка,
#+ то большинство ядер будет падать в воду.
#  Незначительная часть ядер будет падать на твердую почву.
#
#  Если произвести достаточно большое число неприцельных выстрелов по данному участку,
#+ то отношение попаданий в воду к общему числу выстрелов будет примерно равно
#+ значению PI/4.
#
#  По той простой причине, что стрельба фактически ведется только
#+ по правому верхнему квадранту карты.
#  (Предыдущее описание было несколько упрощено.)
#
#  Теоретически, чем больше будет произведено выстрелов, тем точнее будет результат.
#  Однако, сценарий на языке командной оболочки, в отличие от других языков программирования,
#+ в которых доступны операции с плавающей запятой, имеет некоторые ограничения.
#  К сожалению, это делает вычисления менее точными.


DIMENSION=10000  # Длина стороны квадратного участка поверхности.
                 # Он же -- верхний предел для генератора случайных чисел.

MAXSHOTS=1000    # Количество выстрелов.
                 # 10000 выстрелов (или больше) даст лучший результат,
                                                                 # но потребует значительного количества времени.
PMULTIPLIER=4.0  # Масштабирующий коэффициент.

get_random ()
{
SEED=$(head -1 /dev/urandom | od -N 1 | awk '{ print $2 }')
RANDOM=$SEED                                  #  Из примера "seeding-random.sh"

let "rnum = $RANDOM % $DIMENSION"             #  Число не более чем 10000.
echo $rnum
}

distance=        # Объявление глобальной переменной.
hypotenuse ()    # Расчет гипотенузы прямоугольного треугольника.
{                # Из примера "alt-bc.sh".
distance=$(bc -l &lt;&lt; EOF
scale = 0
sqrt ( $1 * $1 + $2 * $2 )
EOF
)
#  Установка "scale" в ноль приводит к округлению результата "вниз",
#+ это и есть то самое ограничение, накладываемое командной оболочкой.
#  Что, к сожалению, снижает точность аппроксимации.
}


# main() {

# Инициализация переменных.
shots=0
splashes=0
thuds=0
Pi=0

while [ "$shots" -lt  "$MAXSHOTS" ]           # Главный цикл.
do

  xCoord=$(get_random)                        # Получить случайные координаты X и Y.
  yCoord=$(get_random)
  hypotenuse $xCoord $yCoord                  #  Гипотенуза = расстоянию.
  ((shots++))

  printf "#%4d   " $shots
  printf "Xc = %4d  " $xCoord
  printf "Yc = %4d  " $yCoord
  printf "Distance = %5d  " $distance         #  Растояние от
                                              #+ центра озера,
                                              #+ с координатами (0,0).

  if [ "$distance" -le "$DIMENSION" ]
  then
    echo -n "ШЛЕП!  "                         # попадание в озеро
    ((splashes++))
  else
    echo -n "БУХ!    "                        # попадание на твердую почву
    ((thuds++))
  fi

  Pi=$(echo "scale=9; $PMULTIPLIER*$splashes/$shots" | bc)
  # Умножение на коэффициент 4.0.
  echo -n "PI ~ $Pi"
  echo

done

echo
echo "После $shots выстрела, примерное значение числа \"пи\" равно $Pi."
# Имеет тенденцию к завышению...
# Вероятно из-за ошибок округления и несовершенства генератора случайных чисел.
echo

# }

exit 0

#  Самое время задуматься над тем, является ли сценарий удобным средством
#+ для выполнения большого количества столь сложных вычислений.
#
#  Тем не менее, этот пример может расцениваться как
#  1) Доказательство возможностей языка командной оболочки.
#  2) Прототип для "обкатки" алгоритма перед тем как перенести
#+    его на высокоуровневые языки программирования компилирующего типа.
</pre>
                  </div>
                </dd>

                <dt><a name="DCREF"></a><strong class="COMMAND">dc</strong></dt>

                <dd>
                  <p>Утилита <strong class="COMMAND">dc</strong> (<strong class="COMMAND">d</strong>esk <strong class="COMMAND">c</strong>alculator) -- это
                  калькулятор, использующий "Обратную Польскую
                  Нотацию", и ориентированный на работу со
                  стеком.</p>

                  <p>Многие стараются избегать испоьзования <strong class="COMMAND">dc</strong>, из-за непривычной формы
                  записи операндов и операций. Однако, <strong class="COMMAND">dc</strong> имеет и своих
                  сторонников.</p>

                  <div class="EXAMPLE">
                    <a name="HEXCONVERT"></a>

                    <p><strong>Пример 12-36. Преобразование чисел из
                    десятичной в шестнадцатиричную систему
                    счисления</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# hexconvert.sh: Преобразование чисел из десятичной в шестнадцатиричную систему счисления.

BASE=16     # Шестнадцатиричная.

if [ -z "$1" ]
then
  echo "Порядок использования: $0 number"
  exit $E_NOARGS
  # Необходим аргумент командной строки.
fi
# Упражнение: добавьте проверку корректности аргумента.


hexcvt ()
{
if [ -z "$1" ]
then
  echo 0
  return    # "Return" 0, если функции не был передан аргумент.
fi

echo ""$1" "$BASE" o p" | dc
#                 "o" устанавливает основание системы счисления для вывода.
#                   "p" выводит число, находящееся на вершине стека.
# См. 'man dc'.
return
}

hexcvt "$1"

exit 0
</pre>
                  </div>

                  <p>Изучение страниц <span class="emphasis"><em class="EMPHASIS">info</em></span> <strong class="COMMAND">dc</strong> позволит детальнее
                  разобраться с утилитой. Однако, отряд
                  "гуру", которые могут похвастать своим
                  знанием этой мощной, но весьма запутанной утилиты,
                  весьма немногочислен.</p>

                  <div class="EXAMPLE">
                    <a name="FACTR"></a>

                    <p><strong>Пример 12-37. Разложение числа на
                    простые множители</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# factr.sh: Разложение числа на простые множители

MIN=2       # Не работает с числами меньше 2.
E_NOARGS=65
E_TOOSMALL=66

if [ -z $1 ]
then
  echo "Порядок использования: $0 number"
  exit $E_NOARGS
fi

if [ "$1" -lt "$MIN" ]
then
  echo "Исходное число должно быть больше или равно $MIN."
  exit $E_TOOSMALL
fi

# Упражнение: Добавьте проверку типа числа (не целые числа должны отвергаться).

echo "Простые множители для числа $1:"
# ---------------------------------------------------------------------------------
echo "$1[p]s2[lip/dli%0=1dvsr]s12sid2%0=13sidvsr[dli%0=1lrli2+dsi!&gt;.]ds.xd1&lt;2" | dc
# ---------------------------------------------------------------------------------
# Автор вышеприведенной строки: Michel Charpentier &lt;charpov@cs.unh.edu&gt;.
# Используется с его разрешения (спасибо).

 exit 0
</pre>
                  </div>
                </dd>

                <dt><a name="AWKMATH"></a><strong class="COMMAND">awk</strong></dt>

                <dd>
                  <p>Еще один способ выполнения математических
                  операций, над числами с плавающей запятой, состоит в
                  создании <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SHWRAPPER">сценария-обертки</a>,
                  использующего математические функции <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AWKREF">awk</a>.</p>

                  <div class="EXAMPLE">
                    <a name="HYPOT"></a>

                    <p><strong>Пример 12-38. Расчет гипотенузы
                    прямоугольного треугольника</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# hypotenuse.sh: Возвращает "гипотенузу" прямоугольного треугольника.
#               ( корень квадратный от суммы квадратов катетов)

ARGS=2                # В сценарий необходимо передать два катета.
E_BADARGS=65          # Ошибка в аргументах.

if [ $# -ne "$ARGS" ] # Проверка количества аргументов.
then
  echo "Порядок использования: `basename $0` катет_1 катет_2"
  exit $E_BADARGS
fi


AWKSCRIPT=' { printf( "%3.7f\n", sqrt($1*$1 + $2*$2) ) } '
#            команды и параметры, передаваемые в awk


echo -n "Гипотенуза прямоугольного треугольника, с катетами $1 и $2, = "
echo $1 $2 | awk "$AWKSCRIPT"

exit 0
</pre>
                  </div>
                </dd>
              </dl>
            </div>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="EXTMISC"></a>12.9. Прочие команды</h2>

            <div class="VARIABLELIST">
              <p><strong><a name="MISCCOMMANDLISTING1"></a>Команды, которые нельзя
              отнести ни к одной из вышеперечисленных
              категорий</strong></p>

              <dl>
                <dt><strong class="COMMAND">jot</strong>, <strong class="COMMAND">seq</strong></dt>

                <dd>
                  <p>Эти утилиты выводят последовательность целых чисел
                  с шагом, заданным пользователем.</p>

                  <p>По-умолчанию, выводимые числа отделяются друг от
                  друга символом перевода строки, однако, с помощью
                  ключа <code class="OPTION">-s</code> может быть задан другой
                  разделитель.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>seq 5</strong></code>
<code class="COMPUTEROUTPUT">1
2
3
4
5</code>



<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>seq -s : 5</strong></code>
<code class="COMPUTEROUTPUT">1:2:3:4:5</code>
             
</pre>
                  <br>
                  <br>

                  <p>Обе утилиты, и <strong class="COMMAND">jot</strong>, и <strong class="COMMAND">seq</strong>, очень удобно
                  использовать для генерации списка аргументов в цикле
                  <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FORLOOPREF1">for</a>.</p>

                  <div class="EXAMPLE">
                    <a name="EX53"></a>

                    <p><strong>Пример 12-39. Использование seq для
                    генерации списка аргументов цикла for</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Утилита "seq"

echo

for a in `seq 80`  # или так:   for a in $( seq 80 )
# То же самое, что и   for a in 1 2 3 4 5 ... 80   (но как экономит время и силы!).
# Можно использовать и 'jot' (если эта утилита имеется в системе).
do
  echo -n "$a "
done      # 1 2 3 4 5 ... 80
# Пример использования вывода команды для генерации
# [списка] аргументов цикла "for".

echo; echo


COUNT=80  # Да, 'seq' допускает указание переменных в качестве параметра.

for a in `seq $COUNT`  # или так:   for a in $( seq $COUNT )
do
  echo -n "$a "
done      # 1 2 3 4 5 ... 80

echo; echo

BEGIN=75
END=80

for a in `seq $BEGIN $END`
#  Если "seq" передаются два аргумента, то первый означает начальное число последовательности,
#+ второй -- последнее,
do
  echo -n "$a "
done      # 75 76 77 78 79 80

echo; echo

BEGIN=45
INTERVAL=5
END=80

for a in `seq $BEGIN $INTERVAL $END`
#  Если "seq" передется три аргумента, то первый аргумент -- начальное число в последовательности,
#+ второй -- шаг последовательности,
#+ и третий -- последнее число в последовательности.
do
  echo -n "$a "
done      # 45 50 55 60 65 70 75 80

echo; echo

exit 0
</pre>
                  </div>
                </dd>

                <dt><a name="GETOPTY"></a><strong class="COMMAND">getopt</strong></dt>

                <dd>
                  <p>Команда <strong class="COMMAND">getopt</strong> служит для разбора
                  командной строки, выделяя из нее ключи -- символы, с
                  предшествующим знаком дефис. Этой утилите имеется,
                  встроенный в Bash, аналог -- <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GETOPTSX">getopts</a>, более мощная и
                  универсальная команда.</p>

                  <div class="EXAMPLE">
                    <a name="EX33A"></a>

                    <p><strong>Пример 12-40. Использование getopt для
                    разбора аргументов командной строки</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# ex33a.sh

# Попробуйте следующие варианты вызова этого сценария.
#   sh ex33a -a
#   sh ex33a -abc
#   sh ex33a -a -b -c
#   sh ex33a -d
#   sh ex33a -dXYZ
#   sh ex33a -d XYZ
#   sh ex33a -abcd
#   sh ex33a -abcdZ
#   sh ex33a -z
#   sh ex33a a
# Объясните полученные результаты.

E_OPTERR=65

if [ "$#" -eq 0 ]
then   # Необходим по меньшей мере один аргумент.
  echo "Порядок использования: $0 -[options a,b,c]"
  exit $E_OPTERR
fi

set -- `getopt "abcd:" "$@"`
# Запись аргументов командной строки в позиционные параметры.
# Что произойдет, если вместо "$@" указать "$*"?

while [ ! -z "$1" ]
do
  case "$1" in
    -a) echo "Опция \"a\"";;
    -b) echo "Опция \"b\"";;
    -c) echo "Опция \"c\"";;
    -d) echo "Опция \"d\" $2";;
     *) break;;
  esac

  shift
done

#  Вместо 'getopt' лучше использовать встроенную команду 'getopts',
#  См. "ex33.sh".

exit 0
</pre>
                  </div>
                </dd>

                <dt><a name="RUNPARTSREF"></a><strong class="COMMAND">run-parts</strong></dt>

                <dd>
                  <p>Команда <strong class="COMMAND">run-parts</strong> <a name="AEN9380" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN9380"><span class="footnote">[33]</span></a> запускает на
                  исполнение все сценарии, в порядке возрастания имен
                  файлов-сценариев, в заданном каталоге. Естественно,
                  файлы сценариев должны иметь права на исполнение.</p>

                  <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DAEMONREF">Демон</a> <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CRONREF">crond</a> вызывает <strong class="COMMAND">run-parts</strong> для запуска
                  сценариев из каталогов <code class="FILENAME">/etc/cron.*</code>.</p>
                </dd>

                <dt><strong class="COMMAND">yes</strong></dt>

                <dd>
                  <p>По-умолчанию, команда <strong class="COMMAND">yes</strong> выводит на <code class="FILENAME">stdout</code> непрерывную
                  последовательность символов <code class="COMPUTEROUTPUT">y</code>, разделенных символами
                  перевода строки. Исполнение команды можно прервать
                  комбинацией клавиш <strong class="KEYCAP">control</strong>-<strong class="KEYCAP">c</strong>. Команду <strong class="COMMAND">yes</strong> можно заставить
                  выводить иную последовательность символов. Теперь
                  самое время задаться вопросом о практической пользе
                  этой команды. Основное применение этой команды
                  состоит в том, что вывод от нее может быть передан,
                  через конвейер, другой команде, ожидающей реакции
                  пользователя. В результате получается, своего рода,
                  слабенькая версия команды <strong class="COMMAND">expect</strong>.</p>

                  <p><code class="USERINPUT"><strong>yes | fsck
                  /dev/hda1</strong></code> запускает <strong class="COMMAND">fsck</strong> в неинтерактивном
                  режиме (будьте осторожны!).</p>

                  <p><code class="USERINPUT"><strong>yes | rm -r
                  dirname</strong></code> имеет тот же эффект, что и <code class="USERINPUT"><strong>rm -rf
                  dirname</strong></code> (будьте осторожны!).</p>

                  <div class="WARNING">
                    <table class="WARNING" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/warning.gif" hspace="5" alt="Warning"></td>

                        <td align="left" valign="top">
                          <p>Внимание! Передача вывода команды <strong class="COMMAND">yes</strong> по конвейеру
                          потенциально опасным командам, таким как <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FSCKREF">fsck</a> или <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FDISKREF">fdisk</a> может дать
                          нежелательные побочные эффекты.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>

                <dt><strong class="COMMAND">banner</strong></dt>

                <dd>
                  <p>Печатает на <code class="FILENAME">stdout</code> заданную строку
                  символов (не более 10), рисуя каждый символ строки
                  при помощи символа '#'. Вывод от команды
                  может быть перенаправлен на принтер.</p>
                </dd>

                <dt><strong class="COMMAND">printenv</strong></dt>

                <dd>
                  <p>Выводит все <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ENVREF">переменные окружения</a> текущего
                  пользователя.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>printenv | grep HOME</strong></code>
<code class="COMPUTEROUTPUT">HOME=/home/bozo</code>
             
</pre>
                  <br>
                  <br>
                </dd>

                <dt><strong class="COMMAND">lp</strong></dt>

                <dd>
                  <p>Команды <strong class="COMMAND">lp</strong> и <strong class="COMMAND">lpr</strong> отправляют файлы в
                  очередь печати <a name="AEN9455" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN9455"><span class="footnote">[34]</span></a> для вывода на
                  принтер. Названия этих команд произошли от "line
                  printers".</p>

                  <p><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>lp file1.txt</strong></code>
                  или <code class="PROMPT">bash</code> <code class="USERINPUT"><strong>lp
                  &lt;file1.txt</strong></code></p>

                  <p>Очень часто используются в комбинации с командой
                  форматированного вывода <strong class="COMMAND">pr</strong>.</p>

                  <p><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>pr -options file1.txt |
                  lp</strong></code></p>

                  <p>Программы подготовки текста к печати, такие как
                  <strong class="COMMAND">groff</strong> и <span class="emphasis"><em class="EMPHASIS">Ghostscript</em></span>, так же
                  могут напрямую взаимодействовать с <strong class="COMMAND">lp</strong>.</p>

                  <p><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>groff -Tascii file.tr |
                  lp</strong></code></p>

                  <p><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>gs -options | lp
                  file.ps</strong></code></p>

                  <p>Команда <strong class="COMMAND">lpq</strong> предназначена для
                  просмотра очереди заданий печати, а <strong class="COMMAND">lprm</strong> -- для удаления
                  заданий из очереди.</p>
                </dd>

                <dt><strong class="COMMAND">tee</strong></dt>

                <dd>
                  <p>[UNIX заимствовал эту идею из водопроводного
                  дела.]</p>

                  <p>Это опрератор перенаправления, но с некоторыми
                  особенностями. Подобно водопроводным трубам, <span class="QUOTE">"tee"</span> позволяет <span class="QUOTE">"направить поток"</span>
                  данных <span class="emphasis"><em class="EMPHASIS">в несколько файлов</em></span> и на
                  stdout одновременно, никак не влияя на сами данные.
                  Эта команда может оказаться очень полезной при
                  отладке.</p>
<pre class="SCREEN">                   tee
                 |------&gt; в файл
                 |
  ===============|===============
  command---&gt;----|-operator--&gt;---&gt; результат работы команд(ы)
  ===============================
             
</pre>
<pre class="PROGRAMLISTING">cat listfile* | sort | tee check.file | uniq &gt; result.file
</pre>
                  (Здесь, в файл <code class="FILENAME">check.file</code> будут записаны
                  данные из всех <span class="QUOTE">"listfile*"</span>, в
                  отсортированном виде до того, как повторяющиеся
                  строки будут удалены командой <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#UNIQREF">uniq</a>.)<br>
                  <br>
                </dd>

                <dt><strong class="COMMAND">mkfifo</strong></dt>

                <dd>
                  <p><a name="NAMEDPIPEREF"></a>Эта, редко встречающаяся,
                  команда создает <span class="emphasis"><em class="EMPHASIS">именованный канал</em></span> -
                  очередь, через который производится обмен данными
                  между процессами. <a name="AEN9514" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN9514"><span class="footnote">[35]</span></a> Как правило, один
                  процесс записывает данные в очередь (FIFO), а другой
                  читает данные из очереди. См. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FIFO">Пример A-17</a>.</p>
                </dd>

                <dt><strong class="COMMAND">pathchk</strong></dt>

                <dd>
                  <p>Производит проверку полного имени файла --
                  проверяет, доступны ли на чтение, каталоги в пути к
                  файлу, и не превышает ли длина полного имени файла
                  255 символов. При несоблюдении одного из условий --
                  возвращает сообщение об ошибке.</p>

                  <p>К сожалению, <strong class="COMMAND">pathchk</strong> не возвращает
                  соответствующего кода ошибки, и потому, в общем-то,
                  бесполезна в сценариях. Вместо нее лучше использовать
                  <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RTIF">операторы проверки файлов</a>.</p>
                </dd>

                <dt><a name="DDREF"></a><strong class="COMMAND">dd</strong></dt>

                <dd>
                  <p>Эта немного непонятная и "страшная"
                  команда (<span class="QUOTE">"data duplicator"</span>)
                  изначально использовалась для переноса данных на
                  магнитной ленте между микрокомпьютерами с ОС UNIX и
                  майнфреймами IBM. Команда <strong class="COMMAND">dd</strong> просто создает копию
                  файла (или <code class="FILENAME">stdin/stdout</code>), выполняя по
                  пути некоторые преобразования. Один из вариантов:
                  преобразование из ASCII в EBCDIC, <a name="AEN9546" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN9546"><span class="footnote">[36]</span></a> <code class="USERINPUT"><strong>dd --help</strong></code>
                  выведет список возможных вариантов преобразований и
                  опций этой мощной утилиты.</p>
<pre class="PROGRAMLISTING"># Изучаем 'dd'.

n=3
p=5
input_file=project.txt
output_file=log.txt

dd if=$input_file of=$output_file bs=1 skip=$((n-1)) count=$((p-n+1)) 2&gt; /dev/null
# Извлечет из $input_file символы с n-го по p-й.




echo -n "hello world" | dd cbs=1 conv=unblock 2&gt; /dev/null
# Выведет "hello world" вертикально.


# Спасибо, S.C.
</pre>
                  <br>
                  <br>

                  <p>Для демонстрации возможностей <strong class="COMMAND">dd</strong>, попробуем перехватить
                  нажатия на клавиши.</p>

                  <div class="EXAMPLE">
                    <a name="DDKEYPRESS"></a>

                    <p><strong>Пример 12-41. Захват нажатых
                    клавиш</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Захват нажатых клавиш.


keypresses=4                      # Количество фиксируемых нажатий.


old_tty_setting=$(stty -g)        # Сохранить настройки терминала.

echo "Нажмите $keypresses клавиши."
stty -icanon -echo                # Запретить канонический режим.
                                  # Запретить эхо-вывод.
keys=$(dd bs=1 count=$keypresses 2&gt; /dev/null)
# 'dd' использует stdin, если "if" не задан.

stty "$old_tty_setting"           # Восстановить настройки терминала.

echo "Вы нажали клавиши \"$keys\"."

# Спасибо S.C.
exit 0
</pre>
                  </div>

                  <p>Команда <strong class="COMMAND">dd</strong> имеет возможность
                  произвольного доступа к данным в потоке.</p>
<pre class="PROGRAMLISTING">echo -n . | dd bs=1 seek=4 of=file conv=notrunc
# Здесь, опция "conv=notrunc" означает, что выходной файлне будет усечен.

# Спасибо, S.C.
</pre>
                  <br>
                  <br>

                  <p>Команда <strong class="COMMAND">dd</strong> может использоваться для
                  создания образов дисков, считывая данные прямо с
                  устройств, таких как дискеты, компакт диски,
                  магнитные ленты (<a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COPYCD">Пример A-6</a>). Обычно она
                  используется для создания загрузочных дискет.</p>

                  <p><code class="USERINPUT"><strong>dd if=kernel-image
                  of=/dev/fd0H1440</strong></code></p>

                  <p>Точно так же, <strong class="COMMAND">dd</strong> может скопировать все
                  содержимое дискеты, даже с неизвестной файловой
                  системой, на жесткий диск в виде файла-образа.</p>

                  <p><code class="USERINPUT"><strong>dd if=/dev/fd0
                  of=/home/bozo/projects/floppy.img</strong></code></p>

                  <p>Еще одно применение <strong class="COMMAND">dd</strong> -- создание временного
                  swap-файла (<a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX73">Пример 28-2</a>) и ram-дисков (<a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RAMDISK">Пример 28-3</a>). Она может
                  создавать даже образы целых разделов жесткого диска,
                  хотя и не рекомендуется делать это без особой на то
                  необходимости.</p>

                  <p>Многие (которые, вероятно, не знают чем себя
                  занять) постоянно придумывают все новые и новые
                  области применения команды <strong class="COMMAND">dd</strong>.</p>

                  <div class="EXAMPLE">
                    <a name="BLOTOUT"></a>

                    <p><strong>Пример 12-42. Надежное удаление
                    файла</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# blotout.sh: Надежно удаляет файл.

#  Этот суенарий записывает случайные данные в заданный файл,
#+ затем записывает туда нули и наконец удаляет файл.
#  После такого удаления даже анализ дисковых секторов
#+ не даст ровным счетом ничего.

PASSES=7         # Количество проходов по файлу.
BLOCKSIZE=1      #  операции ввода/вывода в/из /dev/urandom требуют указания размера блока,
                 #+ иначе вы не получите желаемого результата.
E_BADARGS=70
E_NOT_FOUND=71
E_CHANGED_MIND=72

if [ -z "$1" ]   # Имя файла не указано.
then
  echo "Порядок использования: `basename $0` filename"
  exit $E_BADARGS
fi

file=$1

if [ ! -e "$file" ]
then
  echo "Файл \"$file\" не найден."
  exit $E_NOT_FOUND
fi

echo; echo -n "Вы совершенно уверены в том, что желаете уничтожить \"$file\" (y/n)? "
read answer
case "$answer" in
[nN]) echo "Передумали? Операция отменена."
      exit $E_CHANGED_MIND
      ;;
*)    echo "Уничтожается файл \"$file\".";;
esac


flength=$(ls -l "$file" | awk '{print $5}')  # Поле с номером 5 -- это длина файла.

pass_count=1

echo

while [ "$pass_count" -le "$PASSES" ]
do
  echo "Проход #$pass_count"
  sync         # Вытолкнуть буферы.
  dd if=/dev/urandom of=$file bs=$BLOCKSIZE count=$flength
               # Заполнить файл случайными данными.
  sync         # Снова вытолкнуть буферы.
  dd if=/dev/zero of=$file bs=$BLOCKSIZE count=$flength
               # Заполнить файл нулями.
  sync         # Снова вытолкнуть буферы.
  let "pass_count += 1"
  echo
done


rm -f $file    # Наконец удалить изрядно "подпорченный" файл.
sync           # Вытолкнуть буферы в последний раз.

echo "Файл \"$file\" уничтожен."; echo


#  Это довольно надежный, хотя и достаточно медленный способ уничтожения файлов.
#+ Более эффективно это делает команда "shred",
#+ входящая в состав пакета GNU "fileutils".

#  Уничтоженный таким образом файл, не сможет быть восстановлен обычными методами.
#  Однако...
#+ эта метода вероятно НЕ сможет противостоять аналитическим службам
#+ из СООТВЕТСТВУЮЩИХ ОРГАНОВ


#  Tom Vier разработал пакет "wipe", который более надежно стирает файлы
#+ чем этот простой сценарий.
#     http://www.ibiblio.org/pub/Linux/utils/file/wipe-2.0.0.tar.bz2

#  Для более глубоко изучения проблемы надежного удаления файлов,
#+ рекомендую обратиться к cnfnmt Peter Gutmann,
#+     "Secure Deletion of Data From Magnetic and Solid-State Memory".
#         http://www.cs.auckland.ac.nz/~pgut001/pubs/secure_del.html


exit 0
</pre>
                  </div>
                </dd>

                <dt><a name="ODREF"></a><strong class="COMMAND">od</strong></dt>

                <dd>
                  <p>Команда <strong class="COMMAND">od</strong> (<span class="emphasis"><em class="EMPHASIS">octal dump</em></span>) производит
                  преобразование ввода (или файла) в один или несколько
                  форматов, в соответствии с указанными опциями. При
                  отсутствии опций используется восьмеричный формат
                  (опция -o). Эта команда полезна при просмотре или
                  обработке файлов с двоичными данными, например <code class="FILENAME">/dev/urandom</code>. См. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SEEDINGRANDOM">Пример 9-26</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RND">Пример 12-10</a>.</p>
                </dd>

                <dt><strong class="COMMAND">hexdump</strong></dt>

                <dd>
                  <p>Выводит дамп двоичных данных из файла в
                  восьмеричном, шестнадцатиричном, десятичном виде или
                  в виде ASCII. Эту команду, с массой оговорок, можно
                  назвать эквивалентом команды of <strong class="COMMAND">od</strong>.</p>
                </dd>

                <dt><strong class="COMMAND">objdump</strong></dt>

                <dd>
                  <p>Отображает содержимое исполняемого или объектного
                  файла либо в шестнадцатиричной форме, либо в виде
                  дизассемблерного листинга (с ключом <code class="OPTION">-d</code>).</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>objdump -d /bin/ls</strong></code>
<code class="COMPUTEROUTPUT">/bin/ls:     file format elf32-i386

 Disassembly of section .init:

 080490bc &lt;.init&gt;:
  80490bc:       55                      push   %ebp
  80490bd:       89 e5                   mov    %esp,%ebp
  . . .</code>
             
</pre>
                  <br>
                  <br>
                </dd>

                <dt><strong class="COMMAND">mcookie</strong></dt>

                <dd>
                  <p>Эта команда создает псевдослучайные
                  шестнадцатиричные 128-битные числа, так называемые
                  <span class="QUOTE">"magic cookie"</span>,
                  обычно используется X-сервером в качестве <span class="QUOTE">"сигнатуры"</span>
                  авторизации. В сценариях может использоваться как
                  малоэффективный генератор случайных чисел.</p>
<pre class="PROGRAMLISTING">random000=`mcookie | sed -e '2p'`
# 'sed' удаляет посторонние символы.
</pre>
                  <br>
                  <br>

                  <p>Конечно, для тех же целей, сценарий может
                  использовать <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MD5SUMREF">md5</a>.</p>
<pre class="PROGRAMLISTING"># Сценарий вычисляет контрольную сумму для самого себя.
random001=`md5sum $0 | awk '{print $1}'`
# 'awk' удаляет имя файла.
</pre>
                  <br>
                  <br>

                  <p>С помощью <strong class="COMMAND">mcookie</strong> можно создавать
                  <span class="QUOTE">"уникальные"</span> имена
                  файлов.</p>

                  <div class="EXAMPLE">
                    <a name="TEMPFILENAME"></a>

                    <p><strong>Пример 12-43. Генератор имен
                    файлов</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# tempfile-name.sh:  Генератор имен временных файлов

BASE_STR=`mcookie`   # 32-символьный (128 бит) magic cookie.
POS=11               # Произвольная позиция в строке magic cookie.
LEN=5                # $LEN последовательных символов.

prefix=temp          #  В конце концов это временный ("temp") файл.

suffix=${BASE_STR:POS:LEN}
                     # Извлечь строку, длиной в 5 символов, начиная с позиции 11.

temp_filename=$prefix.$suffix
                     # Сборка имени файла.

echo "Имя временного файла = \"$temp_filename\""

# sh tempfile-name.sh
# Имя временного файла = temp.e19ea

exit 0
</pre>
                  </div>
                </dd>

                <dt><strong class="COMMAND">units</strong></dt>

                <dd>
                  <p>Эта утилита производит преобразование величин из
                  одних единиц измерения в другие. Как правило
                  вызывается в интерактивном режиме, ниже приводится
                  пример использования <strong class="COMMAND">units</strong> в сценарии.</p>

                  <div class="EXAMPLE">
                    <a name="UNITCONVERSION"></a>

                    <p><strong>Пример 12-44. Преобразование метров в
                    мили</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# unit-conversion.sh


convert_units ()  # Принимает в качестве входных параметров единицы измерения.
{
  cf=$(units "$1" "$2" | sed --silent -e '1p' | awk '{print $2}')
  # Удаляет все кроме коэффициентов преобразования.
  echo "$cf"
}

Unit1=miles
Unit2=meters
cfactor=`convert_units $Unit1 $Unit2`
quantity=3.73

result=$(echo $quantity*$cfactor | bc)

echo "В $quantity милях $result метров."

#  Что произойдет, если в функцию передать несовместимые единицы измерения,
#+ например "acres" (акры) and "miles" (мили)?

exit 0
</pre>
                  </div>
                </dd>

                <dt><strong class="COMMAND">m4</strong></dt>

                <dd>
                  <p>Не команда, а клад, <strong class="COMMAND">m4</strong> -- это мощный фильтр
                  обработки макроопределений, <a name="AEN9671" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN9671"><span class="footnote">[37]</span></a> фактически -- целый
                  язык программирования. Изначально создававшаяся как
                  препроцессор для <span class="emphasis"><em class="EMPHASIS">RatFor</em></span>, <strong class="COMMAND">m4</strong> оказалась очень полезной
                  и как самостоятельная утилита. Фактически, <strong class="COMMAND">m4</strong> сочетает в себе
                  функциональные возможности <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EVALREF">eval</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TRREF">tr</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AWKREF">awk</a>, и дополнительно
                  предоставляет обширные возможности по созданию новых
                  макроопределений.</p>

                  <p>В апрельском выпуске, за 2002 год, журнала <!--noindex--><a href="http://www.linuxjournal.com/" target="_top">Linux Journal</a><!--/noindex--> вы найдете
                  замечательную статью, описывающую возможности утилиты
                  <strong class="COMMAND">m4</strong>.</p>

                  <div class="EXAMPLE">
                    <a name="M4"></a>

                    <p><strong>Пример 12-45. Пример работы с
                    m4</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# m4.sh: Демонстрация некоторых возможносией макропроцессора m4

# Строки
string=abcdA01
echo "len($string)" | m4                           # 7
echo "substr($string,4)" | m4                      # A01
echo "regexp($string,[0-1][0-1],\&amp;Z)" | m4     # 01Z

# Арифметика
echo "incr(22)" | m4                               # 23
echo "eval(99 / 3)" | m4                           # 33

exit 0
</pre>
                  </div>
                </dd>

                <dt><strong class="COMMAND">doexec</strong></dt>

                <dd>
                  <p>Команда <strong class="COMMAND">doexec</strong> предоставляет
                  возможность передачи произвольного списка аргументов
                  внешней программе. В частности, передавая <code class="VARNAME">argv[0]</code> (для сценариев
                  соответствует специальной переменной <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#POSPARAMREF1">$0</a>), можно вызвать
                  программу под другим именем, определяя тем самым, ее
                  реакцию.</p>

                  <p>Например, Пусть в каталоге <code class="FILENAME">/usr/local/bin</code> имеется
                  программа с именем <span class="QUOTE">"aaa"</span>, которая при
                  вызове <strong class="COMMAND">doexec /usr/local/bin/aaa
                  list</strong> выведет список всех файлов в текущем
                  каталоге, имена которых начинаются с символа <span class="QUOTE">"a"</span>, а при вызове той
                  же самой программы как <strong class="COMMAND">doexec /usr/local/bin/aaa
                  delete</strong> , она удалит эти файлы.</p>

                  <div class="NOTE">
                    <table class="NOTE" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                        <td align="left" valign="top">
                          <p>Естественно, реакция программы на свое
                          собственное имя должна быть реализована в
                          коде программы, для сценария на языке
                          командной оболочки это может выглядеть
                          примерно так:</p>
<pre class="PROGRAMLISTING">case `basename $0` in
"name1" ) реакция на вызов под именем name1;;
"name2" ) реакция на вызов под именем name2;;
"name3" ) реакция на вызов под именем name3;;
*       ) действия по-умолчанию;;
esac
</pre>
                          <br>
                          <br>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>
              </dl>
            </div>
          </div>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="SYSTEM"></a>Глава 13. Команды системного
          администрирования</h1>

          <p>Примеры использования большинства этих команд вы найдете в
          сценариях начальной загрузки и остановки системы, в каталогах
          <code class="FILENAME">/etc/rc.d</code>. Они, обычно, вызываются
          пользователем root и используются для администрирования
          системы или восстановления файловой системы. Эти команды
          должны использоваться с большой осторожностью, так как
          некоторые из них могут разрушить систему, при неправильном
          использовании.</p>

          <div class="VARIABLELIST">
            <p><strong><a name="USERSGROUPS1"></a>Пользователи и группы</strong></p>

            <dl>
              <dt><strong class="COMMAND">users</strong></dt>

              <dd>
                <p>Выведет список всех зарегистрировавшихся
                пользователей. Она, до некоторой степени, является
                эквивалентом команды <strong class="COMMAND">who -q</strong>.</p>
              </dd>

              <dt><strong class="COMMAND">groups</strong></dt>

              <dd>
                <p>Выводит список групп, в состав которых входит
                текущий пользователь. Эта команда соответствует
                внутренней переменной <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GROUPSREF">$GROUPS</a>, но выводит названия
                групп, а не их числовые идентификаторы.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>groups</strong></code>
<code class="COMPUTEROUTPUT">bozita cdrom cdwriter audio xgrp</code>

<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo $GROUPS</strong></code>
<code class="COMPUTEROUTPUT">501</code>
</pre>
              </dd>

              <dt><strong class="COMMAND">chown</strong>, <strong class="COMMAND">chgrp</strong></dt>

              <dd>
                <p>Команда <strong class="COMMAND">chown</strong> изменяет владельца
                файла или файлов. Эта команда полезна в случаях, когда
                <code class="REPLACEABLE"><em>root</em></code> хочет передать
                монопольное право на файл от одного пользователя
                другому. Обычный пользователь не в состоянии изменить
                владельца файла, за исключением своих собственных
                файлов.</p>
<pre class="SCREEN"><code class="PROMPT">root#</code> <code class="USERINPUT"><strong>chown bozo *.txt</strong></code>

             
</pre>
                <br>
                <br>

                <p>Команда <strong class="COMMAND">chgrp</strong> изменяет группу,
                которой принадлежит файл или файлы. Чтобы изменить
                группу, вы должны быть владельцем файла (при этом
                должны входить в состав указываемой группы) или
                привилегированным пользователем (<code class="REPLACEABLE"><em>root</em></code>).</p>
<pre class="PROGRAMLISTING">chgrp --recursive dunderheads *.data
#  Группа "dunderheads" станет владельцем всех файлов "*.data"
#+ во всех подкаталогах текущей директории ($PWD) (благодаря ключу "--recursive").
</pre>
                <br>
                <br>
              </dd>

              <dt><strong class="COMMAND">useradd</strong>, <strong class="COMMAND">userdel</strong></dt>

              <dd>
                <p>Команда <strong class="COMMAND">useradd</strong> добавляет учетную
                запись нового пользователя в систему и создает домашний
                каталог для данного пользователя. Противоположная, по
                смыслу, команда <strong class="COMMAND">userdel</strong> удаляет учетную
                запись пользователя из системы. <a name="AEN9791" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN9791"><span class="footnote">[38]</span></a> и удалит
                соответствующие файлы.</p>

                <div class="NOTE">
                  <table class="NOTE" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                      <td align="left" valign="top">
                        <p>Команда <strong class="COMMAND">adduser</strong> является
                        синонимом для <strong class="COMMAND">useradd</strong> и, как
                        правило, является обычной символической ссылкой
                        на <strong class="COMMAND">useradd</strong>.</p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </dd>

              <dt><a name="IDREF"></a><strong class="COMMAND">id</strong></dt>

              <dd>
                <p>Команда <strong class="COMMAND">id</strong> выводит идентификатор
                пользователя (реальный и эффективный) и идентификаторы
                групп, в состав которых входит пользователь. По сути --
                выводит содержимое переменных <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#UIDREF">$UID</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EUIDREF">$EUID</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GROUPSREF">$GROUPS</a>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>id</strong></code>
<code class="COMPUTEROUTPUT">uid=501(bozo) gid=501(bozo) groups=501(bozo),22(cdrom),80(cdwriter),81(audio)</code>

<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo $UID</strong></code>
<code class="COMPUTEROUTPUT">501</code>
</pre>

                <p>См. также <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AMIROOT">Пример 9-5</a>.</p>
              </dd>

              <dt><a name="WHOREF"></a><strong class="COMMAND">who</strong></dt>

              <dd>
                <p>Выводит список пользователей, работающих в настоящий
                момент в системе.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>who</strong></code>
<code class="COMPUTEROUTPUT">bozo  tty1     Apr 27 17:45
 bozo  pts/0    Apr 27 17:46
 bozo  pts/1    Apr 27 17:47
 bozo  pts/2    Apr 27 17:49</code>
             
</pre>
                <br>
                <br>

                <p>С ключом <code class="OPTION">-m</code> -- выводит информацию только о
                текущем пользователе. Если число аргументов,
                передаваемых команде, равно двум, то это эквивалентно
                вызову <strong class="COMMAND">who -m</strong>, например <strong class="COMMAND">who am i</strong> или <strong class="COMMAND">who The Man</strong>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>who -m</strong></code>
<code class="COMPUTEROUTPUT">localhost.localdomain!bozo  pts/2    Apr 27 17:49</code>
             
</pre>
                <br>
                <br>

                <p><a name="WHOAMIREF"></a><strong class="COMMAND">whoami</strong> -- похожа на <strong class="COMMAND">who -m</strong>, но выводит только имя
                пользователя.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>whoami</strong></code>
<code class="COMPUTEROUTPUT">bozo</code>
             
</pre>
                <br>
                <br>
              </dd>

              <dt><strong class="COMMAND">w</strong></dt>

              <dd>
                <p>Выводит информацию о системе, список пользователей,
                подключенных к системе и процессы, связанные с
                пользователями. Это расширенная версия команды <strong class="COMMAND">who</strong>. Вывод от команды <strong class="COMMAND">w</strong> может быть передан по
                конвейеру команде <strong class="COMMAND">grep</strong>, с целью поиска
                требуемого пользователя и/или процесса.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>w | grep startx</strong></code>
<code class="COMPUTEROUTPUT">bozo  tty1     -                 4:22pm  6:41   4.47s  0.45s  startx</code>
</pre>
              </dd>

              <dt><strong class="COMMAND">logname</strong></dt>

              <dd>
                <p>Выводит имя текущего пользователя (из файла <code class="FILENAME">/var/run/utmp</code>). Это довольно
                близкий эквивалент команды <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WHOAMIREF">whoami</a>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>logname</strong></code>
<code class="COMPUTEROUTPUT">bozo</code>

<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>whoami</strong></code>
<code class="COMPUTEROUTPUT">bozo</code>
</pre>

                <p>Однако...</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>su</strong></code>
<code class="COMPUTEROUTPUT">Password: ......</code>

<code class="PROMPT">bash#</code> <code class="USERINPUT"><strong>whoami</strong></code>
<code class="COMPUTEROUTPUT">root</code>
<code class="PROMPT">bash#</code> <code class="USERINPUT"><strong>logname</strong></code>
<code class="COMPUTEROUTPUT">bozo</code>
</pre>
              </dd>

              <dt><a name="SUREF"></a><strong class="COMMAND">su</strong></dt>

              <dd>
                <p>Команда предназначена для запуска программы или
                сценария от имени другого пользователя. <strong class="COMMAND">su rjones</strong> -- запускает
                командную оболочку от имени пользователя <span class="emphasis"><em class="EMPHASIS">rjones</em></span>. Запуск команды
                <strong class="COMMAND">su</strong> без параметров означает
                запуск командной оболочки от имени привилегированного
                пользователя <span class="emphasis"><em class="EMPHASIS">root</em></span>. См. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FIFO">Пример A-17</a>.</p>
              </dd>

              <dt><strong class="COMMAND">sudo</strong></dt>

              <dd>
                <p>Исполняет заданную команду от имени пользователя
                root (или другого пользователя).</p>
<pre class="PROGRAMLISTING">#!/bin/bash

# Доступ к "секретным" файлам.
sudo cp /root/secretfile /home/bozo/secret
</pre>
                <br>
                <br>

                <p>Имена пользователей, которым разрешено использовать
                команду <strong class="COMMAND">sudo</strong>, хранятся в файле <code class="FILENAME">/etc/sudoers</code>.</p>
              </dd>

              <dt><strong class="COMMAND">passwd</strong></dt>

              <dd>
                <p>Устанавливает или изменяет пароль пользователя.</p>

                <p>Команда <strong class="COMMAND">passwd</strong> может использоваться в
                сценариях, но это плохая практика.</p>
<pre class="PROGRAMLISTING">#!/bin/bash
#  set-new-password.sh: Плохая идея.
#  Этот сценарий должен запускаться пользователем root,
#+ а еще лучше -- не запускать его вообще.

ROOT_UID=0         # $UID root = 0.
E_WRONG_USER=65    # Не root?

if [ "$UID" -ne "$ROOT_UID" ]
then
  echo; echo "Только root может запускать этот сценарий."; echo
  exit $E_WRONG_USER
else
  echo; echo "Вам не следовало бы запускать этот сценарий."
fi


username=bozo
NEWPASSWORD=security_violation

echo "$NEWPASSWORD" | passwd --stdin "$username"
#  Ключ '--stdin' указывает 'passwd'
#+ получить новый пароль со stdin (или из конвейера).

echo; echo "Пароль пользователя $username изменен!"

# Использование команды 'passwd' в сценариях -- опасно.

exit 0
</pre>
                <br>
                <br>
              </dd>

              <dt><strong class="COMMAND">ac</strong></dt>

              <dd>
                <p>Выводит время работы пользователей, основываясь на
                записях в файле <code class="FILENAME">/var/log/wtmp</code>. Это одна из
                утилит пакета GNU acct.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>ac</strong></code>
 <code class="COMPUTEROUTPUT">       total       68.08</code>
</pre>
              </dd>

              <dt><strong class="COMMAND">last</strong></dt>

              <dd>
                <p>Выводит информацию о <span class="emphasis"><em class="EMPHASIS">последних</em></span> входах/выходах
                пользователей в ситему, основываясь на записях в файле
                <code class="FILENAME">/var/log/wtmp</code>. Эта команда может
                отображать информацию об удаленных (в смысле -- с
                удаленного терминала) соединениях.</p>
              </dd>

              <dt><strong class="COMMAND">newgrp</strong></dt>

              <dd>
                <p>Позволяет сменить активную группу пользователя.
                Пользователь остается в системе и текущий каталог не
                изменяется, но права доступа к файлам вычисляются в
                соответствии с новыми реальным и эффективным
                идентификаторами группы. Эта команда используется
                довольно редко, так как пользователь, обычно, является
                членом нескольких групп.</p>
              </dd>
            </dl>
          </div>

          <div class="VARIABLELIST">
            <p><strong><a name="TERMINALSSYS1"></a>Терминалы</strong></p>

            <dl>
              <dt><strong class="COMMAND">tty</strong></dt>

              <dd>
                <p>Выводит имя терминала текущего пользователя.
                Обратите внимание: каждое отдельное окно xterm
                считается отдельным терминалом.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>tty</strong></code>
<code class="COMPUTEROUTPUT">/dev/pts/1</code>
</pre>
              </dd>

              <dt><a name="STTYREF"></a><strong class="COMMAND">stty</strong></dt>

              <dd>
                <p>Выводит и/или изменяет настройки терминала. Эта
                сложная команда используется в сценариях для управления
                поведением терминала.</p>

                <div class="EXAMPLE">
                  <a name="ERASE"></a>

                  <p><strong>Пример 13-1. Установка символа
                  "забоя"</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# erase.sh: Использование команды "stty" для смены клавиши "забоя" при чтении ввода.

echo -n "Как Вас зовут? "
read name                      # Попробуйте стереть последние символы при вводе.
                               # Все работает.
echo "Вас зовут $name."

stty erase '#'                 # Теперь, чтобы стереть символ нужно использовать клавишу "#".
echo -n "Как Вас зовут? "
read name                      # Попробуйте стереть последние символы при вводе с помощью "#".
echo "Вас зовут $name."

exit 0
</pre>
                </div>

                <div class="EXAMPLE">
                  <a name="SECRETPW"></a>

                  <p><strong>Пример 13-2. невидимый пароль: Отключение
                  эхо-вывода на терминал</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

echo
echo -n "Введите пароль "
read passwd
echo "Вы ввели пароль: $passwd"
echo -n "Если кто-нибудь в это время заглядывал Вам через плечо, "
echo "то теперь он знает Ваш пароль."

echo &amp;&amp; echo  # Две пустых строки через "and list".

stty -echo    # Отключить эхо-вывод.

echo -n "Введите пароль еще раз "
read passwd
echo
echo "Вы ввели пароль: $passwd"
echo

stty echo     # Восстановить эхо-вывод.

exit 0
</pre>
                </div>

                <p>Перехват нажатия на клавиши с помощью <strong class="COMMAND">stty</strong>.</p>

                <div class="EXAMPLE">
                  <a name="KEYPRESS"></a>

                  <p><strong>Пример 13-3.</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# keypress.sh: Определение нажатых клавиш.

echo

old_tty_settings=$(stty -g)   # Сохранить прежние настройки.
stty -icanon
Keypress=$(head -c1)          # или $(dd bs=1 count=1 2&gt; /dev/null)
                              # для других, не GNU, систем

echo
echo "Была нажата клавиша \""$Keypress"\"."
echo

stty "$old_tty_settings"      # Восстановить прежние настройки.

# Спасибо, Stephane Chazelas.

exit 0
</pre>
                </div>

                <p>См. также <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TIMEOUT">Пример 9-3</a>.</p>

                <table class="SIDEBAR" border="1" cellpadding="5">
                  <tbody><tr>
                    <td>
                      <div class="SIDEBAR">
                        <a name="AEN10028"></a>

                        <p><strong>терминалы и их режимы
                        работы</strong></p>

                        <p>Как правило, терминалы работают в <span class="emphasis"><em class="EMPHASIS">каноническом</em></span>
                        режиме. Когда пользователь нажимает какую-либо
                        клавишу, то соответствующий ей символ не сразу
                        передается программе, исполняемой в окне
                        терминала. Этот символ поступает сначала в
                        локальный буфер терминала. Когда пользователь
                        нажимает клавишу <strong class="KEYCAP">ENTER</strong>, то тогда все
                        содержимое буфера передается программе.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>stty -a</strong></code>
<code class="COMPUTEROUTPUT">speed 9600 baud; rows 36; columns 96; line = 0;
intr = ^C; quit = ^\; erase = ^H; kill = ^U; eof = ^D; eol = &lt;undef&gt;; eol2 = &lt;undef&gt;;
start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O;
...
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt</code>
               
</pre>
                        <br>
                        <br>

                        <p>В каноническом режиме можно использовать
                        символы редактирования во время ввода.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>cat &gt; filexxx</strong></code>
<code class="USERINPUT"><strong>wha&lt;ctl-W&gt;I&lt;ctl-H&gt;foo bar&lt;ctl-U&gt;hello world&lt;ENTER&gt;</strong></code>
<code class="USERINPUT"><strong>&lt;ctl-D&gt;</strong></code>
<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>cat filexxx</strong></code>
<code class="COMPUTEROUTPUT">hello world</code>
<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>bash$ wc -c &lt; file</strong></code>
<code class="COMPUTEROUTPUT">13</code>
               
</pre>
                        Процесс в терминале получит только 13 символов
                        (12 алфавитных символов и символ перевода
                        строки), хотя пользователь нажал 26 клавиш.
                        <br>
                        <br>

                        <p>В неканоническом (<span class="QUOTE">"сыром"</span>)
                        режиме, каждая нажатая клавиша (включая
                        специальные символы редактирования, такие как
                        <strong class="KEYCAP">ctl-H</strong>) сразу же
                        передается исполняющемуся в терминале
                        процессу.</p>

                        <p>Под управлением Bash, базовый терминальный
                        редактор заменяется более сложным терминальным
                        редактором Bash. Например, если вы нажмете
                        комбинацию клавиш <strong class="KEYCAP">ctl-A</strong> в командной
                        строке Bash, то вы не увидите символов <strong class="KEYCAP">^A</strong>, которые выводит
                        терминал, вместо этого Bash получит символ
                        <strong class="KEYCAP">\1</strong>, проанализирует его
                        и переместит курсор в начало строки.</p>

                        <p><span class="emphasis"><em class="EMPHASIS">Stephane
                        Chazelas</em></span></p>
                      </div>
                    </td>
                  </tr>
                </tbody></table>
              </dd>

              <dt><strong class="COMMAND">tset</strong></dt>

              <dd>
                <p>Выводит или изменяет настройки терминала. Это более
                слабая версия <strong class="COMMAND">stty</strong>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>tset -r</strong></code>
<code class="COMPUTEROUTPUT">Terminal type is xterm-xfree86.
Kill is control-U (^U).
Interrupt is control-C (^C).</code>
             
</pre>
                <br>
                <br>
              </dd>

              <dt><strong class="COMMAND">setserial</strong></dt>

              <dd>
                <p>Настройка параметров последовательного порта. Эта
                команда должна запускаться пользователем, обладающим
                привилегиями root. Эту команду можно встретить в
                сценариях настройки системы.</p>
<pre class="PROGRAMLISTING"># Взято из /etc/pcmcia/serial :

IRQ=`setserial /dev/$DEVICE | sed -e 's/.*IRQ: //'`
setserial /dev/$DEVICE irq 0 ; setserial /dev/$DEVICE irq $IRQ
</pre>
                <br>
                <br>
              </dd>

              <dt><strong class="COMMAND">getty</strong>, <strong class="COMMAND">agetty</strong></dt>

              <dd>
                <p>Программа <strong class="COMMAND">getty</strong> или <strong class="COMMAND">agetty</strong> запускается процессом
                init и обслуживает процедуру входа пользователя в
                систему. Эти команды не используются в сценариях.</p>
              </dd>

              <dt><a name="MESGREF"></a><strong class="COMMAND">mesg</strong></dt>

              <dd>
                <p>Разрешает или запрещает доступ к терминалу текущего
                пользователя командой <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WRITEREF">write</a>.</p>

                <div class="TIP">
                  <table class="TIP" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/tip.gif" hspace="5" alt="Tip"></td>

                      <td align="left" valign="top">
                        <p>Наверное это очень неприятно, когда, во
                        время работы над текстовым файлом, в окне
                        терминала, прямо среди текста, вдруг появляется
                        предложение заказать пиццу. Поэтому, при работе
                        в многопользовательской системе, вам наверняка
                        захочется отключить доступ к своему
                        терминалу.</p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </dd>

              <dt><strong class="COMMAND">wall</strong></dt>

              <dd>
                <p>Имя этой команды -- аббревиатура от <span class="QUOTE">"<a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WRITEREF">write</a> all"</span>, т.е.,
                передать сообщение всем пользователям на все терминалы
                в сети. Это, в первую очередь, инструмет
                администратора, который можно использовать, например,
                для оповещения всех пользователей о предстоящей, в
                ближайшее время, перезагрузке системы (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX70">Пример 17-2</a>).</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>wall System going down for maintenance in 5 minutes!</strong></code>
<code class="COMPUTEROUTPUT">Broadcast message from bozo (pts/1) Sun Jul  8 13:53:27 2001...

 System going down for maintenance in 5 minutes!</code>
             
</pre>
                <br>
                <br>

                <div class="NOTE">
                  <table class="NOTE" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                      <td align="left" valign="top">
                        <p>Если доступ к терминалу был закрыт командой
                        <strong class="COMMAND">mesg</strong>, то сообщение на
                        этом терминале выводиться не будет.</p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </dd>

              <dt><strong class="COMMAND">dmesg</strong></dt>

              <dd>
                <p>Выводит все сообщения, выдаваемые системой во время
                загрузки на <code class="FILENAME">stdout</code>. Очень полезная утилита
                для отладочных целей. Вывод <strong class="COMMAND">dmesg</strong> может анализироваться с
                помощью <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GREPREF">grep</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SEDREF">sed</a> или <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AWKREF">awk</a> внутри сценария.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>dmesg | grep hda</strong></code>
<code class="COMPUTEROUTPUT">Kernel command line: ro root=/dev/hda2
 hda: IBM-DLGA-23080, ATA DISK drive
 hda: 6015744 sectors (3080 MB) w/96KiB Cache, CHS=746/128/63
 hda: hda1 hda2 hda3 &lt; hda5 hda6 hda7 &gt; hda4</code>
             
</pre>
                <br>
                <br>
              </dd>
            </dl>
          </div>

          <div class="VARIABLELIST">
            <p><strong><a name="STATISTICSSYS1"></a>Информационные и статистические
            утилиты</strong></p>

            <dl>
              <dt><strong class="COMMAND">uname</strong></dt>

              <dd>
                <p>Выводит на <code class="FILENAME">stdout</code> имя системы. С ключом <code class="OPTION">-a</code>, выводит подробную информацию,
                содержащую имя системы, имя узла (то есть имя, под
                которым система известна в сети), версию операционной
                системы, наименование модификации операционной системы,
                аппаратную архитектуру (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX41">Пример 12-4</a>).</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>uname -a</strong></code>
<code class="COMPUTEROUTPUT">Linux localhost.localdomain 2.2.15-2.5.0 #1 Sat Feb 5 00:13:43 EST 2000 i686 unknown</code>

<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>uname -s</strong></code>
<code class="COMPUTEROUTPUT">Linux</code>
</pre>
              </dd>

              <dt><strong class="COMMAND">arch</strong></dt>

              <dd>
                <p>Выводит тип аппаратной платформы компьютерв.
                Эквивалентна команде <strong class="COMMAND">uname -m</strong>. См. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CASECMD">Пример 10-26</a>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>arch</strong></code>
<code class="COMPUTEROUTPUT">i686</code>

<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>uname -m</strong></code>
<code class="COMPUTEROUTPUT">i686</code>
</pre>
              </dd>

              <dt><strong class="COMMAND">lastcomm</strong></dt>

              <dd>
                <p>Выводит информацию, о ранее выполненных командах, из
                файла <code class="FILENAME">/var/account/pacct</code>.
                Дополнительно могут указываться команда и пользователь.
                Это одна из утилит пакета GNU acct.</p>
              </dd>

              <dt><strong class="COMMAND">lastlog</strong></dt>

              <dd>
                <p>Выводит список всех пользователей, с указанием
                времени последнего входа в систему. Данные берутся из
                файла <code class="FILENAME">/var/log/lastlog</code>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>lastlog</strong></code>
<code class="COMPUTEROUTPUT">root          tty1                      Fri Dec  7 18:43:21 -0700 2001
 bin                                     **Never logged in**
 daemon                                  **Never logged in**
 ...
 bozo          tty1                      Sat Dec  8 21:14:29 -0700 2001</code>



<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>lastlog | grep root</strong></code>
<code class="COMPUTEROUTPUT">root          tty1                      Fri Dec  7 18:43:21 -0700 2001</code>
             
</pre>
                <br>
                <br>

                <div class="CAUTION">
                  <table class="CAUTION" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                      <td align="left" valign="top">
                        <p>Исполнение этой команды будет завершаться
                        неудачей, если пользователь, вызвавший утилиту,
                        не имеет прав на чтение файла <code class="FILENAME">/var/log/lastlog</code>.</p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </dd>

              <dt><strong class="COMMAND">lsof</strong></dt>

              <dd>
                <p>Выводит детальный список открытых, в настоящий
                момент времени, файлов в виде таблицы. В таблице
                указаны -- владелец файла, размер файла, тип файла,
                процесс, открывший файл, и многое другое. Само собой
                разумеется, что вывод команды <strong class="COMMAND">lsof</strong> может быть обработан, в
                конвейере, с помощью утилит <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GREPREF">grep</a> и/или <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AWKREF">awk</a>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>lsof</strong></code>
<code class="COMPUTEROUTPUT">COMMAND    PID    USER   FD   TYPE     DEVICE    SIZE     NODE NAME
 init         1    root  mem    REG        3,5   30748    30303 /sbin/init
 init         1    root  mem    REG        3,5   73120     8069 /lib/ld-2.1.3.so
 init         1    root  mem    REG        3,5  931668     8075 /lib/libc-2.1.3.so
 cardmgr    213    root  mem    REG        3,5   36956    30357 /sbin/cardmgr
 ...</code>
             
</pre>
                <br>
                <br>
              </dd>

              <dt><strong class="COMMAND">strace</strong></dt>

              <dd>
                <p>Диагностическая и отладочная утилита,
                предназначенная для трассировки системных вызовов и
                сигналов. В простейшем случае, запускается как: <strong class="COMMAND">strace COMMAND</strong>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>strace df</strong></code>
<code class="COMPUTEROUTPUT">execve("/bin/df", ["df"], [/* 45 vars */]) = 0
 uname({sys="Linux", node="bozo.localdomain", ...}) = 0
 brk(0)                                  = 0x804f5e4
 ...</code>
           
</pre>
                <br>
                <br>

                <p>Эквивалентна команде <strong class="COMMAND">truss</strong>.</p>
              </dd>

              <dt><strong class="COMMAND">nmap</strong></dt>

              <dd>
                <p>Сканер сетевых портов. Эта утилита сканирует сервер
                в поисках открытых портов и сервисов. Это очень важный
                инструмент, используемый для поиска уязвимостей при
                настройке системы.</p>
<pre class="PROGRAMLISTING">#!/bin/bash

SERVER=$HOST                           # localhost.localdomain (127.0.0.1).
PORT_NUMBER=25                         # порт службы SMTP.

nmap $SERVER | grep -w "$PORT_NUMBER"  # Проверить -- открыт ли данный порт?
#              grep -w -- поиск только целых слов,
#+             так, например, порт 1025 будет пропущен.

exit 0

# 25/tcp     open        smtp
</pre>
                <br>
                <br>
              </dd>

              <dt><a name="FREEREF"></a><strong class="COMMAND">free</strong></dt>

              <dd>
                <p>Показывает информацию об использовании памяти, в
                табличной форме. Вывод команды может быть
                проанализирован с помощью <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GREPREF">grep</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AWKREF">awk</a> или <strong class="COMMAND">Perl</strong>. Команда <strong class="COMMAND">procinfo</strong> тоже выводит эту
                информацию, среди всего прочего.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <strong class="COMMAND">free</strong>
 <code class="COMPUTEROUTPUT">               total       used       free     shared    buffers     cached
   Mem:         30504      28624       1880      15820       1608       16376
   -/+ buffers/cache:      10640      19864
   Swap:        68540       3128      65412</code>
</pre>

                <p>Показать размер неиспользуемой памяти RAM:</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <strong class="COMMAND">free | grep Mem | awk '{ print $4 }'</strong>
<code class="COMPUTEROUTPUT">1880</code>
</pre>
              </dd>

              <dt><a name="PROCINFOREF"></a><strong class="COMMAND">procinfo</strong></dt>

              <dd>
                <p>Извлекает и выводит информацию из <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DEVPROCREF">файловой системы <code class="FILENAME">/proc</code></a>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>procinfo | grep Bootup</strong></code>
<code class="COMPUTEROUTPUT">Bootup: Wed Mar 21 15:15:50 2001    Load average: 0.04 0.21 0.34 3/47 6829</code>
</pre>
              </dd>

              <dt><a name="LSDEVREF"></a><strong class="COMMAND">lsdev</strong></dt>

              <dd>
                <p>Список аппаратных устройств в системе.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>lsdev</strong></code>
<code class="COMPUTEROUTPUT">Device            DMA   IRQ  I/O Ports
 ------------------------------------------------
 cascade             4     2
 dma                          0080-008f
 dma1                         0000-001f
 dma2                         00c0-00df
 fpu                          00f0-00ff
 ide0                     14  01f0-01f7 03f6-03f6
 ...</code>
             
</pre>
                <br>
                <br>
              </dd>

              <dt><a name="DUREF"></a><strong class="COMMAND">du</strong></dt>

              <dd>
                <p>Выводит сведения о занимаемом дисковом пространстве
                в каталоге и вложенных подкаталогах. Если каталог не
                указан, то по-умолчанию выводятся сведения о текущем
                каталоге.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <strong class="COMMAND">du -ach</strong>
<code class="COMPUTEROUTPUT">1.0k    ./wi.sh
 1.0k    ./tst.sh
 1.0k    ./random.file
 6.0k    .
 6.0k    total</code>
</pre>
              </dd>

              <dt><a name="DFREF"></a><strong class="COMMAND">df</strong></dt>

              <dd>
                <p>Выводит в табличной форме сведения о смонтированных
                файловых системах.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <strong class="COMMAND">df</strong>
<code class="COMPUTEROUTPUT">Filesystem           1k-blocks      Used Available Use% Mounted on
/dev/hda5               273262     92607    166547  36% /
/dev/hda8               222525    123951     87085  59% /home
/dev/hda7              1408796   1075744    261488  80% /usr</code>
</pre>
              </dd>

              <dt><strong class="COMMAND">stat</strong></dt>

              <dd>
                <p>Дает подробную информацию о заданном файле (каталоге
                или файле устройства) или наборе файлов.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>stat test.cru</strong></code>
 <code class="COMPUTEROUTPUT"> File: "test.cru"
   Size: 49970        Allocated Blocks: 100          Filetype: Regular File
   Mode: (0664/-rw-rw-r--)         Uid: (  501/ bozo)  Gid: (  501/ bozo)
 Device:  3,8   Inode: 18185     Links: 1
 Access: Sat Jun  2 16:40:24 2001
 Modify: Sat Jun  2 16:40:24 2001
 Change: Sat Jun  2 16:40:24 2001</code>
             
</pre>
                <br>
                <br>

                <p>Если заданный файл отсутствует, то <strong class="COMMAND">stat</strong> вернет сообщение об
                ошибке.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>stat nonexistent-file</strong></code>
<code class="COMPUTEROUTPUT">nonexistent-file: No such file or directory</code>
             
</pre>
                <br>
                <br>
              </dd>

              <dt><a name="VMSTATREF"></a><strong class="COMMAND">vmstat</strong></dt>

              <dd>
                <p>Выводит информацию о виртуальной памяти.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>vmstat</strong></code>
 <code class="COMPUTEROUTPUT">  procs                      memory    swap          io system         cpu
 r  b  w   swpd   free   buff  cache  si  so    bi    bo   in    cs  us  sy id
 0  0  0      0  11040   2636  38952   0   0    33     7  271    88   8   3 89</code>
           
</pre>
                <br>
                <br>
              </dd>

              <dt><strong class="COMMAND">netstat</strong></dt>

              <dd>
                <p>Показывает сведения о сетевой подсистеме, такие как:
                таблицы маршрутизации и активные соединения. Эта
                утилита получает сведения из <code class="FILENAME">/proc/net</code> (<a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DEVPROC">Глава 27</a>). См. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CONSTAT">Пример 27-2</a>.</p>

                <p><strong class="COMMAND">netstat -r</strong> -- эквивалентна
                команде <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ROUTEREF">route</a>.</p>
              </dd>

              <dt><a name="UPTIMEREF"></a><strong class="COMMAND">uptime</strong></dt>

              <dd>
                <p>Показывает количество времени, прошедшего с момента
                последней перезагрузки системы.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>uptime</strong></code>
<code class="COMPUTEROUTPUT">10:28pm  up  1:57,  3 users,  load average: 0.17, 0.34, 0.27</code>
</pre>
              </dd>

              <dt><a name="HNAMEREF"></a><strong class="COMMAND">hostname</strong></dt>

              <dd>
                <p>Выводит имя узла (сетевое имя системы). С помощью
                этой команды устанавливается сетевое имя системы в
                сценарии <code class="FILENAME">/etc/rc.d/rc.sysinit</code>.
                Эквивалентна команде <strong class="COMMAND">uname -n</strong> и внутренней
                переменной <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#HOSTNAMEREF">$HOSTNAME</a>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>hostname</strong></code>
<code class="COMPUTEROUTPUT">localhost.localdomain</code>

<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo $HOSTNAME</strong></code>
<code class="COMPUTEROUTPUT">localhost.localdomain</code>
</pre>
              </dd>

              <dt><a name="HOSTIDREF"></a><strong class="COMMAND">hostid</strong></dt>

              <dd>
                <p>Выводит 32-битный шестнадцатиричный идентификатор
                системы.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>hostid</strong></code>
<code class="COMPUTEROUTPUT">7f0100</code>
</pre>
                <br>
                <br>

                <div class="NOTE">
                  <table class="NOTE" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                      <td align="left" valign="top">
                        <p>Эта команда генерирует <span class="QUOTE">"уникальный"</span>
                        числовой идентификатор системы. Некоторые
                        программные продукты используют этот
                        идентификатор в процедуре регистрации. К
                        сожалению, при генерации идентификатора,
                        <strong class="COMMAND">hostid</strong> использует
                        только IP адрес системы, переводя его в
                        шестнадцатиричное представление и переставляя
                        местами пары байт.</p>

                        <p>Обычно, IP адрес системы можно найти в файле
                        <code class="FILENAME">/etc/hosts</code>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>cat /etc/hosts</strong></code>
<code class="COMPUTEROUTPUT">127.0.0.1               localhost.localdomain localhost</code>
</pre>
                        <br>
                        <br>

                        <p>Переставив местами байты, попарно, в
                        начальном адресе <code class="USERINPUT"><strong>127.0.0.1</strong></code>, мы
                        получим <code class="USERINPUT"><strong>0.127.1.0</strong></code>, в
                        шестнадцатиричном представлении это будет <code class="USERINPUT"><strong>007f0100</strong></code>, что
                        в точности совпадает с приведенным выше
                        результатом выполнения <strong class="COMMAND">hostid</strong>. Наверняка
                        можно найти несколько миллионов компьютеров с
                        таким же <span class="QUOTE">"уникальным"</span>
                        идентификатором.</p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </dd>

              <dt><strong class="COMMAND">sar</strong></dt>

              <dd>
                <p>Команда <strong class="COMMAND">sar</strong> (system activity report)
                выводит очень подробную статистику о функционировании
                операционной системы. Эту команду можно найти в
                отдельных коммерческих дистрибутивах UNIX-систем. Она,
                как правило, не входит в базовый комплект пакетов
                Linux-систем. Она входит в состав пакета <!--noindex--><a href="http://perso.wanadoo.fr/sebastien.godard/" target="_top">sysstat utilities</a><!--/noindex-->, автор: <a href="mailto:sebastien.godard@wanadoo.fr" target="_top">Sebastien Godard</a>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>sar</strong></code>
<code class="COMPUTEROUTPUT">Linux 2.4.7-10 (localhost.localdomain)         12/31/2001

 10:30:01 AM       CPU     %user     %nice   %system     %idle
 10:40:00 AM       all      1.39      0.00      0.77     97.84
 10:50:00 AM       all     76.83      0.00      1.45     21.72
 11:00:00 AM       all      1.32      0.00      0.69     97.99
 11:10:00 AM       all      1.17      0.00      0.30     98.53
 11:20:00 AM       all      0.51      0.00      0.30     99.19
 06:30:00 PM       all    100.00      0.00    100.01      0.00
 Average:          all      1.39      0.00      0.66     97.95</code>
          
</pre>
              </dd>

              <dt><strong class="COMMAND">readelf</strong></dt>

              <dd>
                <p>Показывает сведения о заданном бинарном файле
                формата <span class="emphasis"><em class="EMPHASIS">elf</em></span>. Входит в состав
                пакета <span class="emphasis"><em class="EMPHASIS">binutils</em></span>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>readelf -h /bin/bash</strong></code>
<code class="COMPUTEROUTPUT">ELF Header:
   Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
   Class:                             ELF32
   Data:                              2's complement, little endian
   Version:                           1 (current)
   OS/ABI:                            UNIX - System V
   ABI Version:                       0
   Type:                              EXEC (Executable file)
   . . .</code>
</pre>
              </dd>

              <dt><strong class="COMMAND">size</strong></dt>

              <dd>
                <p>Команда <strong class="COMMAND">size [/path/to/binary]</strong>
                выведет информацию о размерах различных сегментов в
                исполняемых или библиотечных файлах. В основном
                используется программистами.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>size /bin/bash</strong></code>
 <code class="COMPUTEROUTPUT">  text    data     bss     dec     hex filename
  495971   22496   17392  535859   82d33 /bin/bash</code>
             
</pre>
                <br>
                <br>
              </dd>
            </dl>
          </div>

          <div class="VARIABLELIST">
            <p><strong><a name="SYSLOG1"></a>Системный журнал</strong></p>

            <dl>
              <dt><strong class="COMMAND">logger</strong></dt>

              <dd>
                <p>Добавляет в системный журнал (<code class="FILENAME">/var/log/messages</code>) сообщение от
                пользователя. Для добавления сообщения пользователь не
                должен обладать привилегиями суперпользователя.</p>
<pre class="PROGRAMLISTING">logger Experiencing instability in network connection at 23:10, 05/21.
# Теперь попробуйте дать команду 'tail /var/log/messages'.
</pre>
                <br>
                <br>

                <p>Встраивая вызов <strong class="COMMAND">logger</strong> в сценарии, вы
                получаете возможность заносить отладочную информацию в
                системный журнал <code class="FILENAME">/var/log/messages</code>.</p>
<pre class="PROGRAMLISTING">logger -t $0 -i Logging at line "$LINENO".
# Ключ "-t" задает тэг записи в журнале.
# Ключ "-i" -- записывает ID процесса.

# tail /var/log/message
# ...
# Jul  7 20:48:58 localhost ./test.sh[1712]: Logging at line 3.
</pre>
                <br>
                <br>
              </dd>

              <dt><strong class="COMMAND">logrotate</strong></dt>

              <dd>
                <p>Эта утилита производит манипуляции над системным
                журналом: ротация, сжатие, удаление и/или отправляет
                его по электронной почте, по мере необходимости. Как
                правило, утилита <strong class="COMMAND">logrotate</strong> вызывается демоном
                <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CRONREF">crond</a> ежедневно.</p>

                <p>Добавляя соответствующие строки в <code class="FILENAME">/etc/logrotate.conf</code>, можно
                заставить <strong class="COMMAND">logrotate</strong> обрабатывать не
                только системный журнал, но и ваш личный.</p>
              </dd>
            </dl>
          </div>

          <div class="VARIABLELIST">
            <p><strong><a name="JOBCONTROLSYS1"></a>Управление
            заданиями</strong></p>

            <dl>
              <dt><strong class="COMMAND">ps</strong></dt>

              <dd>
                <p><code class="REPLACEABLE"><em>P</em></code>rocess <code class="REPLACEABLE"><em>S</em></code>tatistics: Список
                исполняющихся в данный момент процессов. Обычно
                вызывается с ключами <code class="OPTION">ax</code>, вывод команды может быть
                обработан командами <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GREPREF">grep</a> или <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SEDREF">sed</a>, с целью поиска требуемого
                процесса (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX44">Пример 11-10</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PIDID">Пример 27-1</a>).</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>ps ax | grep sendmail</strong></code>
<code class="COMPUTEROUTPUT">295 ?     S      0:00 sendmail: accepting connections on port 25</code>
</pre>
              </dd>

              <dt><strong class="COMMAND">pstree</strong></dt>

              <dd>
                <p>Список исполняющихся процессов в виде <span class="QUOTE">"дерева"</span>. С ключом <code class="OPTION">-p</code> -- вместе с именами процессов
                отображает их PID.</p>
              </dd>

              <dt><strong class="COMMAND">top</strong></dt>

              <dd>
                <p>Выводит список наиболее активных процессов. С ключом
                <code class="OPTION">-b</code> -- отображение ведется в
                обычном текстовом режиме, что дает возможность анализа
                вывода от команды внутри сценария.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>top -b</strong></code>
 <code class="COMPUTEROUTPUT"> 8:30pm  up 3 min,  3 users,  load average: 0.49, 0.32, 0.13
 45 processes: 44 sleeping, 1 running, 0 zombie, 0 stopped
 CPU states: 13.6% user,  7.3% system,  0.0% nice, 78.9% idle
 Mem:    78396K av,   65468K used,   12928K free,       0K shrd,    2352K buff
 Swap:  157208K av,       0K used,  157208K free                   37244K cached

   PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME COMMAND
   848 bozo      17   0   996  996   800 R     5.6  1.2   0:00 top
     1 root       8   0   512  512   444 S     0.0  0.6   0:04 init
     2 root       9   0     0    0     0 SW    0.0  0.0   0:00 keventd
   ...</code>
             
</pre>
                <br>
                <br>
              </dd>

              <dt><strong class="COMMAND">nice</strong></dt>

              <dd>
                <p>Запускает фоновый процесс с заданным приоритетом.
                Приоритеты могут задаваться числом из диапазона от 19
                (низший приоритет) до -20 (высший приоритет). Но только
                <span class="emphasis"><em class="EMPHASIS">root</em></span> может указать
                значение приоритета меньше нуля (отрицательные
                значения). См. так же команды <strong class="COMMAND">renice</strong>, <strong class="COMMAND">snice</strong> и <strong class="COMMAND">skill</strong>.</p>
              </dd>

              <dt><strong class="COMMAND">nohup</strong></dt>

              <dd>
                <p>Запуск команд в режиме игнорирования сигналов
                прерывания и завершения, что предотвращает завершение
                работы команды даже если пользователь, запустивший ее,
                вышел из системы. Если после команды не указан символ
                <span class="TOKEN">&amp;</span>, то она будет исполняться
                как процесс "переднего плана". Если вы
                собираетесь использовать <strong class="COMMAND">nohup</strong> в сценариях, то вам
                потребуется использовать его в связке с командой <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WAITREF">wait</a>, чтобы не породить процесс
                "зомби".</p>
              </dd>

              <dt><a name="PIDOFREF"></a><strong class="COMMAND">pidof</strong></dt>

              <dd>
                <p>Возвращает идентификатор процесса <span class="emphasis"><em class="EMPHASIS">(pid)</em></span> по его имени.
                Поскольку многие команды управления процессами, такие
                как <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#KILLREF">kill</a> и <strong class="COMMAND">renice</strong>, требуют указать <span class="emphasis"><em class="EMPHASIS">pid</em></span> процесса, а не его
                имя, то <strong class="COMMAND">pidof</strong> может сослужить
                неплохую службу при идентификации процесса по его
                имени. Эта коменда может рассматриваться как
                приблизительный эквивалент внутренней переменной <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PPIDREF">$PPID</a>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>pidof xclock</strong></code>
<code class="COMPUTEROUTPUT">880</code>
             
</pre>
                <br>
                <br>

                <div class="EXAMPLE">
                  <a name="KILLPROCESS"></a>

                  <p><strong>Пример 13-4. Использование команды pidof
                  при остановке процесса</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# kill-process.sh

NOPROCESS=2

process=xxxyyyzzz  # Несуществующий процесс.
# Только в демонстрационных целях...
# ... чтобы не уничтожить этим сценарием какой-нибудь процесс.
#
# Если с помощью этого сценария вы задумаете разрыватть связь с Internet, то
#     process=pppd

t=`pidof $process`       # Поиск pid (process id) процесса $process.
# pid требует команда 'kill' (невозможно остановить процесс, указав его имя).

if [ -z "$t" ]           # Если процесс с таким именем не найден, то 'pidof' вернет null.
then
  echo "Процесс $process не найден."
  exit $NOPROCESS
fi

kill $t                  # В некоторых случаях может потребоваться 'kill -9'.

# Здесь нужно проверить -- был ли уничтожен процесс.
# Возможно так: " t=`pidof $process` ".


# Этот сценарий мог бы быть заменен командой
#    kill $(pidof -x process_name)
# но это было бы не так поучительно.

exit 0
</pre>
                </div>
              </dd>

              <dt><strong class="COMMAND">fuser</strong></dt>

              <dd>
                <p>Возвращает идентификаторы процессов, использующих
                указанный файл(ы) или каталог. С ключом <code class="OPTION">-k</code>, завершает найденные процессы.
                Может с успехом использоваться для защиты системы,
                особенно в сценариях разграничения доступа к системным
                службам.</p>
              </dd>

              <dt><a name="CRONREF"></a><strong class="COMMAND">crond</strong></dt>

              <dd>
                <p>Планировщик заданий. С его помощью выполняются такие
                задачи, как очистка и удаление устаревших файлов
                системных журналов, обновление базы данных <span class="DATABASE">slocate</span>. Это
                суперпользовательская версия команды <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ATREF">at</a> (хотя любой пользователь может
                создать собственную таблицу <code class="FILENAME">crontab</code>). Эта утилита
                запускается как фоновый процесс-<a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DAEMONREF">daemon</a> и выполняет задания,
                находящиеся в файле <code class="FILENAME">/etc/crontab</code>.</p>
              </dd>
            </dl>
          </div>

          <div class="VARIABLELIST">
            <p><strong><a name="RUNCONTROLSYS1"></a>Команды управления процессами и
            загрузкой</strong></p>

            <dl>
              <dt><strong class="COMMAND">init</strong></dt>

              <dd>
                <p><strong class="COMMAND">init</strong> -- <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FORKREF">предок (родитель)</a> всех процессов в
                системе. Вызывается на последнем этапе загрузки системы
                и определяет уровень загрузки (runlevel) из файла <code class="FILENAME">/etc/inittab</code>.</p>
              </dd>

              <dt><strong class="COMMAND">telinit</strong></dt>

              <dd>
                <p>Символическая ссылка на <strong class="COMMAND">init</strong> -- инструмент для смены
                уровня загрузки (runlevel), как правило используется
                при обслуживании системы или восстановлении файловой
                системы. Может быть вызвана только суперпользователем.
                Эта команда может быть очень опасна, при неумелом
                обращении -- прежде чем использовать ее, убедитесь в
                том, что вы совершенно точно понимаете что делаете!</p>
              </dd>

              <dt><strong class="COMMAND">runlevel</strong></dt>

              <dd>
                <p>Выводит предыдущий и текущий уровни загрузки
                (runlevel). Уровень загрузки может иметь одно из 6
                значений: <code class="LITERAL">0</code> -- остановка системы, <code class="LITERAL">1</code> -- однопользовательский режим,
                <code class="LITERAL">2</code> или <code class="LITERAL">3</code> -- многопользовательский режим,
                <code class="LITERAL">5</code> -- многопользовательский режим
                и запуск X Window, <code class="LITERAL">6</code> -- перезагрузка. Уровни
                загрузки определяются из файла <code class="FILENAME">/var/run/utmp</code>.</p>
              </dd>

              <dt><strong class="COMMAND">halt</strong>, <strong class="COMMAND">shutdown</strong>, <strong class="COMMAND">reboot</strong></dt>

              <dd>
                <p>Набор команд для остановки системы, обычно перед
                выключением питания.</p>
              </dd>
            </dl>
          </div>

          <div class="VARIABLELIST">
            <p><strong><a name="NETWORKSYS1"></a>Команды для работы с
            сетью</strong></p>

            <dl>
              <dt><strong class="COMMAND">ifconfig</strong></dt>

              <dd>
                <p>Утилита конфигурирования и запуска сетевых
                интерфейсов. Чаще всего используется в сценариях
                начальной загрузки системы, для настройки и запуска
                сетевых интерфейсов или для их остановки перед
                остановкой или перезагрузкой.</p>
<pre class="PROGRAMLISTING"># Фрагменты кода из /etc/rc.d/init.d/network

# ...

# Проверка сетевой полсистемы.
[ ${NETWORKING} = "no" ] &amp;&amp; exit 0

[ -x /sbin/ifconfig ] || exit 0

# ...

for i in $interfaces ; do
  if ifconfig $i 2&gt;/dev/null | grep -q "UP" &gt;/dev/null 2&gt;&amp;1 ; then
    action "Останавливается $i: " ./ifdown $i boot
  fi
# Ключ "-q", характерный для GNU-версии "grep", означает "quiet" ("молча"), т.е. подавляет вывод.
# Поэтому нет необходимости переадресовывать вывод на /dev/null.

# ...

echo "В настоящее время активны устройства:"
echo `/sbin/ifconfig | grep ^[a-z] | awk '{print $1}'`
#                            ^^^^^  скобки необходимы для предотвращения подстановки имен файлов (globbing).
#  Следующий код делает то же самое.
#    echo $(/sbin/ifconfig | awk '/^[a-z]/ { print $1 })'
#    echo $(/sbin/ifconfig | sed -e 's/ .*//')
#  Спасибо S.C. за комментарии.
</pre>
                См. также <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ONLINE">Пример 29-6</a>.<br>
                <br>
              </dd>

              <dt><a name="ROUTEREF"></a><strong class="COMMAND">route</strong></dt>

              <dd>
                <p>Выводит сведения о таблице маршрутизации ядра или
                вносит туда изменения.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>route</strong></code>
<code class="COMPUTEROUTPUT">Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
 pm3-67.bozosisp *               255.255.255.255 UH       40 0          0 ppp0
 127.0.0.0       *               255.0.0.0       U        40 0          0 lo
 default         pm3-67.bozosisp 0.0.0.0         UG       40 0          0 ppp0</code>
             
</pre>
                <br>
                <br>
              </dd>

              <dt><strong class="COMMAND">chkconfig</strong></dt>

              <dd>
                <p>Проверка сетевой конфигурации. Обслуживает список,
                запускаемых на этапе загрузки, сетевых сервисов, список
                сервисов хранится в каталогах <code class="FILENAME">/etc/rc?.d</code> (строго говоря,
                chkconfig работает не только с сетевыми сервисами, а с
                сервисами вообще, не зависимо от того сетевые это
                службы или нет. прим. перев.).</p>

                <p>Изначально эта утилита была перенесена в Red Hat
                Linux из ОС IRIX, <strong class="COMMAND">chkconfig</strong> входит в состав
                далеко не всех дистрибутивов Linux.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>chkconfig --list</strong></code>
<code class="COMPUTEROUTPUT">atd             0:off   1:off   2:off   3:on    4:on    5:on    6:off
rwhod           0:off   1:off   2:off   3:off   4:off   5:off   6:off
 ...</code>
             
</pre>
                <br>
                <br>
              </dd>

              <dt><strong class="COMMAND">tcpdump</strong></dt>

              <dd>
                <p><span class="QUOTE">"Сниффер"</span> (<span class="QUOTE">"sniffer"</span>) сетевых
                пакетов. Инструмент для перехвата и анализа сетевого
                трафика по определенным критериям.</p>

                <p>Дамп трафика ip-пакетов между двумя узлами сети --
                <span class="emphasis"><em class="EMPHASIS">bozoville</em></span> и <span class="emphasis"><em class="EMPHASIS">caduceus</em></span>:</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>tcpdump ip host bozoville and caduceus</strong></code>
             
</pre>
                <br>
                <br>

                <p>Конечно же, вывод команды <strong class="COMMAND">tcpdump</strong> может быть
                проанализирован с помощью <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TPCOMMANDLISTING1">команд обработки текста</a>,
                обсуждавшихся выше.</p>
              </dd>
            </dl>
          </div>

          <div class="VARIABLELIST">
            <p><strong><a name="FILESYSTEMSYS1"></a>Команды для работы с файловыми
            системами</strong></p>

            <dl>
              <dt><strong class="COMMAND">mount</strong></dt>

              <dd>
                <p>Выполняет монтирование файловой системы, обычно на
                устройстве со сменными носителями, такими как дискеты
                или CDROM. Файл <code class="FILENAME">/etc/fstab</code> содержит перечень
                доступных для монтирования файловых систем, разделов и
                устройств, включая опции монтирования, благодаря этому
                файлу, монтирование может производиться автоматически
                или вручеую. Файл <code class="FILENAME">/etc/mtab</code> содержит список
                смонтированных файловых систем и разделов (включая
                виртуальные, такие как <code class="FILENAME">/proc</code>).</p>

                <p><strong class="COMMAND">mount -a</strong> -- монтирует все
                (all) файловые системы и разделы, перечисленные в <code class="FILENAME">/etc/fstab</code>, за исключением тех,
                которые имеют флаг <code class="OPTION">noauto</code>. Эту команду можно
                встретить в сценариях начальной загрузки системы из <code class="FILENAME">/etc/rc.d</code> (<code class="FILENAME">rc.sysinit</code> или нечто
                похожее).</p>
<pre class="PROGRAMLISTING">mount -t iso9660 /dev/cdrom /mnt/cdrom
# Монтирование CDROM-а
mount /mnt/cdrom
# Более короткий и удобный вариант, если точка монтирования /mnt/cdrom описана в /etc/fstab
</pre>
                <br>
                <br>

                <p>Эта команда может даже смонтировать обычный файл как
                блочное устройство. Достигается это за счет связывания
                файла с <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LOOPBACKREF">loopback-устройством</a>. Эту
                возможность можно использовать для проверки ISO9660
                образа компакт-диска перед его записью на болванку. <a name="AEN10873" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN10873"><span class="footnote">[39]</span></a></p>

                <div class="EXAMPLE">
                  <a name="ISOMOUNTREF"></a>

                  <p><strong>Пример 13-5. Проверка образа
                  CD</strong></p>
<pre class="PROGRAMLISTING"># С правами root...

mkdir /mnt/cdtest  # Подготовка точки монтирования.

mount -r -t iso9660 -o loop cd-image.iso /mnt/cdtest   # Монтирование образа диска.
#             ключ "-o loop" эквивалентен "losetup /dev/loop0"
cd /mnt/cdtest     # Теперь проверим образ диска.
ls -alR            # Вывод списка файлов
</pre>
                </div>
              </dd>

              <dt><strong class="COMMAND">umount</strong></dt>

              <dd>
                <p>Отмонтирует смонтированную файловую систему. Перед
                тем как физически вынуть компакт-диск или дискету из
                устройства, это устройство должно быть отмонтировано
                командой <strong class="COMMAND">umount</strong>, иначе файловая
                система может оказаться поврежденной (особенно это
                относится к накопителям на гибких магнитных дисках,
                прим. перев.).</p>
<pre class="PROGRAMLISTING">umount /mnt/cdrom
# Теперь вы можете извлечь диск из привода.
</pre>
                <br>
                <br>

                <div class="NOTE">
                  <table class="NOTE" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                      <td align="left" valign="top">
                        <p>Утилита <strong class="COMMAND">automount</strong>, если она
                        установлена, может выполнять атоматическое
                        монтирование/размонтирование устройств со
                        сменными носителями, такие как дискеты и
                        компакт-диски. На ноутбуках со сменными
                        устройствами FDD и CDROM, такой подход может
                        привести к возникновению определенных
                        проблем.</p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </dd>

              <dt><strong class="COMMAND">sync</strong></dt>

              <dd>
                <p>Принудительный сброс содержимого буферов на жесткий
                диск (синхронизация содержимого буферов ввода-вывода и
                устройства-носителя). Несмотря на то, что нет такой уж
                острой необходимости в этой утилите, тем не менее
                <strong class="COMMAND">sync</strong> придает уверенности
                системным администраторам или пользователям в том, что
                их данные будут сохранены на жестком диске, и не будут
                потеряны в случае какого-либо сбоя. В былые дни,
                команда <code class="USERINPUT"><strong>sync; sync</strong></code>
                (дважды -- для абсолютной уверенности) была упреждающей
                мерой перед перезагрузкой системы.</p>

                <p>Иногда возникает необходимость принудительной
                синхронизации буферов ввода-вывода с содержимым на
                магнитном носителе, как, например, при надежном
                удалении файла (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BLOTOUT">Пример 12-42</a>) или когда
                наблюдаются скачки напряжения в сети
                электроснабжения.</p>
              </dd>

              <dt><a name="LOSETUPREF"></a><strong class="COMMAND">losetup</strong></dt>

              <dd>
                <p>Устанавливает и конфигурирует <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LOOPBACKREF">loopback-устройства</a>.</p>

                <div class="EXAMPLE">
                  <a name="CREATEFS"></a>

                  <p><strong>Пример 13-6. Создание файловой системы в
                  обычном файле</strong></p>
<pre class="PROGRAMLISTING">SIZE=1048576  # 1 Мб

head -c $SIZE &lt; /dev/zero &gt; file  # Создается файл нужного размера.
losetup /dev/loop0 file           # Файл назначается как loopback-устройство.
mke2fs /dev/loop0                 # Создание файловой системы.
mount -o loop /dev/loop0 /mnt     # Монтирование только что созданной файловой системы.

# Спасибо S.C.
</pre>
                </div>
              </dd>

              <dt><strong class="COMMAND">mkswap</strong></dt>

              <dd>
                <p>Создание swap-раздела или swap-файла. Созданный
                swap-раздел (файл) нужно затем подключить командой
                <strong class="COMMAND">swapon</strong>.</p>
              </dd>

              <dt><strong class="COMMAND">swapon</strong>, <strong class="COMMAND">swapoff</strong></dt>

              <dd>
                <p>Разрешает/запрещает использование swap-раздела
                (файла). Эта команда обычно используется во время
                загрузки системы или во время остановки.</p>
              </dd>

              <dt><a name="MKE2FSREF"></a><strong class="COMMAND">mke2fs</strong></dt>

              <dd>
                <p>Создает файловую систему ext2. Должна вызываться с
                правами суперпользователя.</p>

                <div class="EXAMPLE">
                  <a name="ADDDRV"></a>

                  <p><strong>Пример 13-7. Добавление нового жесткого
                  диска</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# Добавление в систему второго жесткого диска.
# Программное конфигурирование. Предполагается, что устройство уже подключено к аппаратуре компьютера.
# Взято из статьи автора документа.
# "Linux Gazette", выпуск #38, http://www.linuxgazette.com.

ROOT_UID=0     # Этот сценарий должен запускать только root.
E_NOTROOT=67   # Код ошибки, если сценарий запущен простым пользователем.

if [ "$UID" -ne "$ROOT_UID" ]
then
  echo "Для запуска этого сценария вы должны обладать правами root."
  exit $E_NOTROOT
fi

# Будьте крайне осторожны!
# Если что-то пойдет не так, то вы можете потерять текущую файловую систему.


NEWDISK=/dev/hdb         # Предполагается, что /dev/hdb -- это новое устройство. Проверьте!
MOUNTPOINT=/mnt/newdisk  # Или выберите иное устройство для монтирования.


fdisk $NEWDISK
mke2fs -cv $NEWDISK1   # Проверка на "плохие" блоки (bad blocks) и подробный вывод.
#  Обратите внимание:    /dev/hdb1, *не* то же самое, что /dev/hdb!
mkdir $MOUNTPOINT
chmod 777 $MOUNTPOINT  # Сделать новое устройство доступным для всех пользователей.


# Теперь проаерим...
# mount -t ext2 /dev/hdb1 /mnt/newdisk
# Попробуйте создать каталог.
# Если получилось -- отмонтируйте устройство и продолжим.

# Последний штрих:
# Добавьте следующую строку в /etc/fstab.
# /dev/hdb1  /mnt/newdisk  ext2  defaults  1 1

exit 0
</pre>
                </div>

                <p>См. также <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CREATEFS">Пример 13-6</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RAMDISK">Пример 28-3</a>.</p>
              </dd>

              <dt><strong class="COMMAND">tune2fs</strong></dt>

              <dd>
                <p>Настройка отдельных параметров файловой системы
                ext2, например счетчик максимального количества
                монтирований без проверки. Должна вызываться с
                привилегиями пользователя root.</p>

                <div class="WARNING">
                  <table class="WARNING" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/warning.gif" hspace="5" alt="Warning"></td>

                      <td align="left" valign="top">
                        <p>Очень опасная утилита. Вы можете
                        использовать ее только на свой страх и риск,
                        поскольку, по неосторожности, вы запросто
                        можете разрушить файловую систему.</p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </dd>

              <dt><strong class="COMMAND">dumpe2fs</strong></dt>

              <dd>
                <p>Выводит на <code class="FILENAME">stdout</code> очень подробную
                информацию о файловой системе. Должна вызываться с
                привилегиями пользователя root.</p>
<pre class="SCREEN"><code class="PROMPT">root#</code> <strong class="COMMAND">dumpe2fs /dev/hda7 | grep 'ount count'</strong>
<code class="COMPUTEROUTPUT">dumpe2fs 1.19, 13-Jul-2000 for EXT2 FS 0.5b, 95/08/09
 Mount count:              6
 Maximum mount count:      20</code>
</pre>
              </dd>

              <dt><strong class="COMMAND">hdparm</strong></dt>

              <dd>
                <p>Выводит или изменяет параметры настройки жесткого
                диска. Должна вызываться с привилегиями пользователя
                root. Потенциально опасна при неправильном
                использовании.</p>
              </dd>

              <dt><a name="FDISKREF"></a><strong class="COMMAND">fdisk</strong></dt>

              <dd>
                <p>Создание или изменение таблицы разделов на
                устройствах хранения информации, обычно -- жестких
                дисках. Должна вызываться с привилегиями пользователя
                root.</p>

                <div class="WARNING">
                  <table class="WARNING" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/warning.gif" hspace="5" alt="Warning"></td>

                      <td align="left" valign="top">
                        <p>Пользуйтесь этой утилитой с особой
                        осторожностью, т.к. при неправильном
                        использовании можно легко разрушить
                        существующую файловую систему.</p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </dd>

              <dt><a name="FSCKREF"></a><strong class="COMMAND">fsck</strong>, <strong class="COMMAND">e2fsck</strong>, <strong class="COMMAND">debugfs</strong></dt>

              <dd>
                <p>Набор команд для проверки, восстановления и отладки
                файловой системы.</p>

                <p><strong class="COMMAND">fsck</strong>: интерфейсная утилита
                для проверки файловых систем в UNIX (может вызывать
                другие утилиты проверки).</p>

                <p><strong class="COMMAND">e2fsck</strong>: проверка файловой
                системы ext2.</p>

                <p><strong class="COMMAND">debugfs</strong>: отладчик файловой
                системы ext2. Одно из применений этой универсальной (и
                опасной) утилиты -- это восстановление удаленных
                файлов. Только для опытных пользователей!</p>

                <div class="CAUTION">
                  <table class="CAUTION" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                      <td align="left" valign="top">
                        <p>Все эти утилиты должны вызываться с
                        привилегиями пользователя root. При
                        неправильном использовании, любая из них может
                        разрушить файловую систему.</p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </dd>

              <dt><strong class="COMMAND">badblocks</strong></dt>

              <dd>
                <p>Выполняет поиск плохих блоков (физические
                повреждения носителей) на устройствах хранения
                информации. Эта команда может использоваться для поиска
                плохих блоков при форматировании вновь устанавливаемых
                жестких дисков или для проверки устройств резервного
                копирования. <a name="AEN11062" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN11062"><span class="footnote">[40]</span></a> Например, <strong class="COMMAND">badblocks /dev/fd0</strong>, проверит
                дискету на наличие поврежденных блоков.</p>

                <p>Утилита <strong class="COMMAND">badblocks</strong> может быть вызвана
                в деструктивном (проверка осуществляется путем записи
                некоторого шаблона в каждый блок, а затем производится
                попытка чтения этого блока) или в недеструктивном
                (неразрушающем -- только чтение) режиме.</p>
              </dd>

              <dt><strong class="COMMAND">mkbootdisk</strong></dt>

              <dd>
                <p>Создание загрузочной дискеты, которая может быть
                использована для загрузки системы, если, например, была
                повреждена MBR (master boot record -- главная
                загрузочная запись). Команда <strong class="COMMAND">mkbootdisk</strong> -- это сценарий на
                языке командной оболочки Bash, автор: Erik Troan,
                располагается в каталоге <code class="FILENAME">/sbin</code>.</p>
              </dd>

              <dt><strong class="COMMAND">chroot</strong></dt>

              <dd>
                <p>CHange ROOT -- смена корневого каталога. Обычно,
                команды и утилиты ориентируются в файловой системе
                посредством переменной <code>$PATH</code>, относительно корневого
                каталога <code class="FILENAME">/</code>. Команда <strong class="COMMAND">chroot</strong> изменяет корневой
                каталог по-умолчанию на другой (рабочий каталог также
                изменяется). Эта утилита, как правило, используется с
                целью защиты системы, например, с ее помощью можно
                ограничить доступ к разделам файловой системы для
                пользователей, подключающихся к системе с помощью <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TELNETREF">telnet</a> (это называется -- <span class="QUOTE">"поместить пользователя в chroot
                окружение"</span>). Обратите внимание: после
                выполнения команды <strong class="COMMAND">chroot</strong> изменяется путь к
                исполняемым файлам системы.</p>

                <p>Команда <code class="USERINPUT"><strong>chroot /opt</strong></code>
                приведет к тому, что все обращения к каталогу <code class="FILENAME">/usr/bin</code> будут переводиться на
                каталог <code class="FILENAME">/opt/usr/bin</code>. Аналогично, <code class="USERINPUT"><strong>chroot /aaa/bbb
                /bin/ls</strong></code> будет пытаться вызвать команду
                <strong class="COMMAND">ls</strong> из каталога <code class="FILENAME">/aaa/bbb/bin</code>, при этом, корневым
                каталогом для ls станет каталог /aaa/bbb. Поместив
                строчку <strong class="COMMAND">alias XX 'chroot /aaa/bbb
                ls'</strong> в пользовательский <code class="FILENAME">~/.bashrc</code>, можно эффективно
                ограничить доступ команде <span class="QUOTE">"XX"</span>, запускаемой
                пользователем, к разделам файловой системы.</p>

                <div class="CAUTION">
                  <table class="CAUTION" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                      <td align="left" valign="top">
                        <p>При изменении корневого каталога, вам
                        наверняка потребуется скопировать системные
                        утилиты и разделяемые библиотеки в новый
                        корневой каталог, поскольку после смены
                        корневого каталога, директории с системными
                        утилитами могут оказаться за пределами нового
                        корневого каталога.</p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </dd>

              <dt><strong class="COMMAND">lockfile</strong></dt>

              <dd>
                <p>Эта утилита входит в состав пакета <strong class="COMMAND">procmail</strong> (<!--noindex--><a href="http://www.procmail.org/" target="_top">www.procmail.org</a><!--/noindex-->). Она создает <span class="emphasis"><em class="EMPHASIS">lock file</em></span>, файл-семафор
                (или, если угодно, файл блокировки), который управляет
                доступом к заданному файлу, устройству или ресурсу.
                Lock file служит признаком того, что данный файл,
                устройство или ресурс <span class="QUOTE">"занят"</span> некоторым
                процессом, и ограничивает (или вообще запрещает) доступ
                к ресурсу другим процессам.</p>

                <p>Файлы блокировок широко применяются для защиты
                системных почтовых каталогов от одновременной записи
                несколькими пользователями, для индикации занятости
                порта модема, и т.п. Сценарии могут использовать файлы
                блокировок для того, чтобы выяснить -- запущен ли тот
                или иной процесс. Обратите внимание: если в сценарии
                будет предпринята попытка создать файл блокировки,
                когда он уже существует, то такой сценарий скорее всего
                зависнет.</p>

                <p>Как правило, файлы блокировки создаются в каталоге
                <code class="FILENAME">/var/lock</code>. Проверка наличия
                файла блокировки может быть проверена примерно таким
                образом:.</p>
<pre class="PROGRAMLISTING">appname=xyzip
# Приложение "xyzip" создает файл блокировки "/var/lock/xyzip.lock".

if [ -e "/var/lock/$appname.lock ]
then
  ...
</pre>
                <br>
                <br>
              </dd>

              <dt><strong class="COMMAND">mknod</strong></dt>

              <dd>
                <p>Создает специальный файл для блочного или
                символьного устройства (может потребоваться при
                установке новых устройств в компьютер).</p>
              </dd>

              <dt><strong class="COMMAND">tmpwatch</strong></dt>

              <dd>
                <p>Автоматически удаляет файлы, к которым не было
                обращений в течение заданного периода времени. Обычно
                вызывается демоном <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CRONREF">crond</a> для удаления устаревших
                файлов системного журнала.</p>
              </dd>

              <dt><strong class="COMMAND">MAKEDEV</strong></dt>

              <dd>
                <p>Утилита предназначена для создания файлов-устройств.
                Должна запускаться с привилегиями пользователя root, в
                каталоге <code class="FILENAME">/dev</code>.</p>
<pre class="SCREEN"><code class="PROMPT">root#</code> <strong class="COMMAND">./MAKEDEV</strong>
</pre>
                Это своего рода расширенная версия утилиты <strong class="COMMAND">mknod</strong>.<br>
                <br>
              </dd>
            </dl>
          </div>

          <div class="VARIABLELIST">
            <p><strong><a name="PERIPHSYS1"></a>Команды резервного
            копирования</strong></p>

            <dl>
              <dt><strong class="COMMAND">dump</strong>, <strong class="COMMAND">restore</strong></dt>

              <dd>
                <p>Команда <strong class="COMMAND">dump</strong> создает резервные копии
                целых файловых систем, обычно используется в крупных
                системах и сетях. <a name="AEN11188" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN11188"><span class="footnote">[41]</span></a> Она считывает
                дисковые разделы и сохраняет их в файле, в двоичном
                формате. Созданные таким образом файлы, могут быть
                сохранены на каком-либо носителе -- на жестком диске
                или магнитной ленте. Команда <strong class="COMMAND">restore</strong> -- <span class="QUOTE">"разворачивает"</span> файлы,
                созданные утилитой <strong class="COMMAND">dump</strong>.</p>
              </dd>

              <dt><strong class="COMMAND">fdformat</strong></dt>

              <dd>
                <p>Выполняет низкоуровневое форматирование дискет.</p>
              </dd>
            </dl>
          </div>

          <div class="VARIABLELIST">
            <p><strong><a name="SYSRESOURCES1"></a>Команды управления системными
            ресурсами</strong></p>

            <dl>
              <dt><strong class="COMMAND">ulimit</strong></dt>

              <dd>
                <p>Устанавливает <span class="emphasis"><em class="EMPHASIS">верхний предел</em></span> для
                системных ресурсов. Как правило вызывается с ключом <code class="OPTION">-f</code>, что означает наложение
                ограничений на размер файлов (<strong class="COMMAND">ulimit -f 1000</strong> ограничит
                размер вновь создаваемых файлов одним мегабайтом). Ключ
                <code class="OPTION">-c</code> ограничивает размер файлов
                coredump (<strong class="COMMAND">ulimit -c 0</strong> запретит создание
                coredump-файлов). Обычно, все ограничения прописываются
                в файле <code class="FILENAME">/etc/profile</code> и/или <code class="FILENAME">~/.bash_profile</code> (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FILES">Глава 26</a>).</p>

                <div class="IMPORTANT">
                  <table class="IMPORTANT" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/important.gif" hspace="5" alt="Important"></td>

                      <td align="left" valign="top">
                        <p>Грамотное использование <strong class="COMMAND">ulimit</strong> поможет
                        избежать нападений, целью которых является
                        исчерпание системных ресурсов, известных под
                        названием <span class="emphasis"><em class="EMPHASIS">fork bomb</em></span>.</p>
<pre class="PROGRAMLISTING">#!/bin/bash

while 1     #  Бесконечный цикл.
do
  $0 &amp;      #  Этот сценарий вызывает сам себя . . .
            #+ порождая дочерние процессы бесконечное число раз . . .
            #+ точнее -- до тех пор, пока не иссякнут системные ресурсы.
done        #  Это печально известный сценарий <span class="QUOTE">"sorcerer's appentice"</span>.

exit 0      #  Сценарий никогда не завершит свою работу.
</pre>
                        <br>
                        <br>

                        <p>Команда <strong class="COMMAND">ulimit -Hu XX</strong> (где
                        <span class="emphasis"><em class="EMPHASIS">XX</em></span> -- это верхний
                        предел количества процессов, которые может
                        запустить пользователь одновременно) в <code class="FILENAME">/etc/profile</code> вызовет
                        аварийное завершение этого сценария, когда
                        количество процессов превысит установленный
                        предел.</p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </dd>

              <dt><strong class="COMMAND">umask</strong></dt>

              <dd>
                <p>Установка маски режима создания файлов. Накладывает
                ограничения на атрибуты по-умлчанию для создаваемых
                файлов. Маска представляет собой восьмеричное значение
                и определяет запрещенные атрибуты файла. Например,
                <strong class="COMMAND">umask 022</strong> удаляет права на
                запись для группы и прочих пользователей (у файлов,
                создававшихся с режимом 777, он оказывается равным 755;
                а режим 666 преобразуется в 644, т.е. 777 NAND 022 =
                755, 666 NAND 022 = 644). <a name="AEN11247" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN11247"><span class="footnote">[42]</span></a> Конечно же,
                впоследствие, пользователь может откорректировать права
                доступа к своему файлу с помощью команды <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CHMODREF">chmod</a>. Как правило, значение
                <strong class="COMMAND">umask</strong> устанавливается в файле
                <code class="FILENAME">/etc/profile</code> и/или <code class="FILENAME">~/.bash_profile</code> (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FILES">Глава 26</a>).</p>
              </dd>

              <dt><strong class="COMMAND">rdev</strong></dt>

              <dd>
                <p>Выводит или изменяет корневое устройство, размер
                RAM-диска или видео режим. Функциональные возможности
                утилиты <strong class="COMMAND">rdev</strong> вообще повторяются
                загрузчиком <strong class="COMMAND">lilo</strong>, но <strong class="COMMAND">rdev</strong> по прежнему остается
                востребованной, например, при установке электронного
                диска (RAM-диск). Это еще одна потенциально опасная,
                при неумелом использовании, утилита.</p>
              </dd>
            </dl>
          </div>

          <div class="VARIABLELIST">
            <p><strong><a name="MODULESSYS1"></a>Команды для работы с модулями
            ядра</strong></p>

            <dl>
              <dt><strong class="COMMAND">lsmod</strong></dt>

              <dd>
                <p>Выводит список загруженных модулей.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>lsmod</strong></code>
<code class="COMPUTEROUTPUT">Module                  Size  Used by
 autofs                  9456   2 (autoclean)
 opl3                   11376   0
 serial_cs               5456   0 (unused)
 sb                     34752   0
 uart401                 6384   0 [sb]
 sound                  58368   0 [opl3 sb uart401]
 soundlow                 464   0 [sound]
 soundcore               2800   6 [sb sound]
 ds                      6448   2 [serial_cs]
 i82365                 22928   2
 pcmcia_core            45984   0 [serial_cs ds i82365]</code>
             
</pre>
                <br>
                <br>

                <div class="NOTE">
                  <table class="NOTE" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                      <td align="left" valign="top">
                        <p>Команда <strong class="COMMAND">cat /proc/modules</strong>
                        выведет на экран эту же информацию.</p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </dd>

              <dt><strong class="COMMAND">insmod</strong></dt>

              <dd>
                <p>Принудительная загрузка модуля ядра (старайтесь
                вместо <strong class="COMMAND">insmod</strong> использовать команду
                <strong class="COMMAND">modprobe</strong>). Должна вызываться
                с привилегиями пользователя root.</p>
              </dd>

              <dt><strong class="COMMAND">rmmod</strong></dt>

              <dd>
                <p>Выгружает модуль ядра. Должна вызываться с
                привилегиями пользователя root.</p>
              </dd>

              <dt><strong class="COMMAND">modprobe</strong></dt>

              <dd>
                <p>Загрузчик модулей, который обычно вызывается из
                сценариев начальной загрузки системы. Должна вызываться
                с привилегиями пользователя root.</p>
              </dd>

              <dt><strong class="COMMAND">depmod</strong></dt>

              <dd>
                <p>Создает файл зависимостей между модулями, обычно
                вызывается из сценариев начальной загрузки системы.</p>
              </dd>
            </dl>
          </div>

          <div class="VARIABLELIST">
            <p><strong><a name="MISCSYS1"></a>Прочие команды</strong></p>

            <dl>
              <dt><strong class="COMMAND">env</strong></dt>

              <dd>
                <p>Запускает указанную программу или сценарий с
                модифицированными <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ENVREF">переменными окружения</a> (не изменяя
                среду системы в целом, изменения касаются только
                окружения запускаемой программы/сценария). Посредством
                <code class="OPTION">[varname=xxx]</code>, устанавливает
                значение переменной окружения <code class="VARNAME">varname</code>, которая будет доступна
                из запускаемой программы/сценария. Без параметров --
                просто выводит список переменных окружения с их
                значениями.</p>

                <div class="NOTE">
                  <table class="NOTE" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                      <td align="left" valign="top">
                        <p>В Bash, и других производных от Bourne
                        shell, имеется возможность установки переменных
                        окружения и запуска программы (или сценария)
                        одной командной строкой.</p>
<pre class="PROGRAMLISTING">var1=value1 var2=value2 commandXXX
# $var1 и $var2 -- будут определены только в окружении для 'commandXXX'.
</pre>
                        <br>
                        <br>
                      </td>
                    </tr>
                  </tbody></table>
                </div>

                <div class="TIP">
                  <table class="TIP" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/tip.gif" hspace="5" alt="Tip"></td>

                      <td align="left" valign="top">
                        <p>В первой строке сценария (<span class="QUOTE">"sha-bang"</span>)
                        можно указать команду <strong class="COMMAND">env</strong>, если путь к
                        командному интерпретатору не известен.</p>
<pre class="PROGRAMLISTING">#! /usr/bin/env perl

print "Этот сценарий, на языке программирования Perl, будет запущен,\n";
print "даже если я не знаю где в системе находится Perl.\n";

# Прекрасно подходит для написания кросс-платформенных сценариев,
# когда Perl может находиться совсем не там, где вы ожидаете.
# Спасибо S.C.
</pre>
                        <br>
                        <br>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </dd>

              <dt><strong class="COMMAND">ldd</strong></dt>

              <dd>
                <p>Выводит список разделяемых библиотек, необходимых
                для исполняемого файла.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>ldd /bin/ls</strong></code>
<code class="COMPUTEROUTPUT">libc.so.6 =&gt; /lib/libc.so.6 (0x4000c000)
/lib/ld-linux.so.2 =&gt; /lib/ld-linux.so.2 (0x80000000)</code>
</pre>
              </dd>

              <dt><a name="WATC"></a><strong class="COMMAND">watch</strong></dt>

              <dd>
                <p>Периодически запускает указанную программу с
                заданным интервалом времени.</p>

                <p>По-умолчанию интервал между запусками принимается
                равным 2 секундам, но может быть изменен ключом <code class="OPTION">-n</code>.</p>
<pre class="PROGRAMLISTING">watch -n 5 tail /var/log/messages
# Выводит последние 10 строк из системного журнала, /var/log/messages, каждые пять секунд.
</pre>
                <br>
                <br>
              </dd>

              <dt><strong class="COMMAND">strip</strong></dt>

              <dd>
                <p>Удаляет отладочную информацию из исполняемого файла.
                Это значительно уменьщает размер исполняемого файла, но
                при этом делает отладку программы невозможной.</p>

                <p>Эту команду часто можно встретить в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MAKEFILEREF">Makefile</a>-ах, и редко -- в
                сценариях на языке командной оболочки.</p>
              </dd>

              <dt><strong class="COMMAND">nm</strong></dt>

              <dd>
                <p>Выводит список символов (используемых в целях
                отладки), содержащихся в откомпилированном двоичном
                файле.</p>
              </dd>

              <dt><strong class="COMMAND">rdist</strong></dt>

              <dd>
                <p>Позволяет на заданных машинах хранить идентичные
                копии файлов. По умолчанию, rdist просматривает только
                те файлы, версия которых на удаленных машинах более
                старая, чем на локальной машине. Это делается
                сравнением последнего времени модификации и размера
                файла на локальной машине и на удаленных.</p>
              </dd>
            </dl>
          </div>

          <p>А теперь, используя полученные нами знания, попробуем
          разобраться с одним из системных сценариев. Один из самых
          коротких и простых -- это <strong class="COMMAND">killall</strong>, который вызывается для
          остановки процессов при перезагрузке или выключении
          компьютера.</p>

          <div class="EXAMPLE">
            <a name="EX55"></a>

            <p><strong>Пример 13-8. Сценарий killall, из каталога <code class="FILENAME">/etc/rc.d/init.d</code></strong></p>
<pre class="PROGRAMLISTING">#!/bin/sh

# --&gt; Комментарии, начинающиеся с "# --&gt;", добавлены автором документа.

# --&gt; Этот сценарий является частью пакета 'rc'-сценариев
# --&gt; Автор: Miquel van Smoorenburg, &lt;miquels@drinkel.nl.mugnet.org&gt;

# --&gt; Этот сценарий характерен для дистрибутива Red Hat
# --&gt; (в других дистрибутивах может отсутствовать).

# Остановить все ненужные сервисы которые еще работают (собственно,
# их уже не должно быть, это лишь формальная проверка, на всякий случай)

for i in /var/lock/subsys/*; do
        # --&gt; Стандартный заголовок цикла for/in, но, поскольку "do"
                                # --&gt; находится в той же самой строке, что и for,
        # --&gt; необходимо разделить их символом ";".
        # Проверяется наличие сценария.
        [ ! -f $i ] &amp;&amp; continue
        # --&gt; Очень интересное использование "И-списка", эквивалентно:
        # --&gt; if [ ! -f "$i" ]; then continue

        # Получить имя подсистемы.
        subsys=${i#/var/lock/subsys/}
        # --&gt; В данном случае совпадает с именем файла.
        # --&gt; Это точный эквивалент subsys=`basename $i`.

        # --&gt;  Таким образом получается имя файла блокировки (если он присутствует,
        # --&gt;+ то это означает, что процесс запущен).
        # --&gt;  См. описание команды "lockfile" выше.


        # Остановить службу.
        if [ -f /etc/rc.d/init.d/$subsys.init ]; then
            /etc/rc.d/init.d/$subsys.init stop
        else
            /etc/rc.d/init.d/$subsys stop
        # --&gt; Останавливает задачу или демона
        # --&gt; посредством встроенной команды 'stop'.
        fi
done
</pre>
          </div>

          <p>Вобщем все довольно понятно. Кроме хитрого манипулирования
          с переменными, при определении имени подсистемы (службы),
          здесь нет ничего нового.</p>

          <div class="FORMALPARA">
            <p><strong>Упражнение 1.</strong> Просмотрите сценарий
            <strong class="COMMAND">halt</strong> в каталоге <code class="FILENAME">/etc/rc.d/init.d</code>. Он по размеру
            немного больше, чем <strong class="COMMAND">killall</strong>, но придерживается той же
            концепции. Создайте копию этого сценария в своем домашнем
            каталоге и поэкспериментируйте с ним (<span class="emphasis"><em class="EMPHASIS">НЕ</em></span> запускайте его с
            привилегиями суперпользователя). Попробуйте запустить его с
            ключами <code class="OPTION">-vn</code> (<code class="USERINPUT"><strong>sh -vn
            scriptname</strong></code>). Добавьте свои комментарии.
            Замените действующие команды на <span class="QUOTE">"echo"</span>.</p>
          </div>

          <div class="FORMALPARA">
            <p><strong>Упражнение 2.</strong> Просмотрите другие, более
            сложные сценарии из <code class="FILENAME">/etc/rc.d/init.d</code>. Попробуйте
            разобраться в их работе. Проверьте их работу, следуя
            рекомендациям, приведенным выше. За дополнительной
            информацией вы можете обратиться к документу <code class="FILENAME">sysvinitfiles</code> в каталоге <code class="FILENAME">/usr/share/doc/initscripts-?.??</code>,
            который входит в пакет документации к <span class="QUOTE">"initscripts"</span>.</p>
          </div>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="COMMANDSUB"></a>Глава 14. Подстановка команд</h1>

          <p><a name="COMMANDSUBREF"></a><strong class="COMMAND">Подстановка команд</strong> -- это
          подстановка результатов выполнения команды <a name="AEN11451" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN11451"><span class="footnote">[43]</span></a> или даже серии команд;
          буквально, эта операция позволяет вызвать команду в другом
          окружении.</p>

          <p><a name="BACKQUOTESREF"></a>Классический пример подстановки
          команд -- использование обратных одиночных кавычек (`...`).
          Команды внутри этих кавычек представляют собой текст
          командной строки.</p>
<pre class="PROGRAMLISTING">script_name=`basename $0`
echo "Имя этого файла-сценария: $script_name."
</pre>
          <br>
          <br>

          <div class="FORMALPARA">
            <p><strong>Вывод от команд может использоваться: как
            аргумент другой команды, для установки значения переменной
            и даже для генерации списка аргументов цикла <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FORLOOPREF1">for</a>.</strong></p>
          </div>
<pre class="PROGRAMLISTING">rm `cat filename`   # здесь <span class="QUOTE">"filename"</span> содержит список удаляемых файлов.
#
# S. C. предупреждает, что в данном случае может возникнуть ошибка "arg list too long".
# Такой вариант будет лучше:   xargs rm -- &lt; filename
# ( -- подходит для случая, когда <span class="QUOTE">"filename"</span> начинается с символа <span class="QUOTE">"-"</span> )

textfile_listing=`ls *.txt`
# Переменная содержит имена всех файлов *.txt в текущем каталоге.
echo $textfile_listing

textfile_listing2=$(ls *.txt)   # Альтернативный вариант.
echo $textfile_listing2
# Результат будет тем же самым.

# Проблема записи списка файлов в строковую переменную состоит в том,
# что символы перевода строки заменяются на пробел.
#
# Как вариант решения проблемы -- записывать список файлов в массив.
#      shopt -s nullglob    # При несоответствии, имя файла игнорируется.
#      textfile_listing=( *.txt )
#
# Спасибо S.C.
</pre>
          <br>
          <br>

          <div class="CAUTION">
            <table class="CAUTION" width="100%" border="0">
              <tbody><tr>
                <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                <td align="left" valign="top">
                  <p>Подстанавливаемая команда может получиться
                  разбитой на отдельные слова.</p>
<pre class="PROGRAMLISTING">COMMAND `echo a b`     # 2 аргумента: a и b

COMMAND "`echo a b`"   # 1 аргумент: "a b"

COMMAND `echo`         # без аргументов

COMMAND "`echo`"       # один пустой аргумент


# Спасибо S.C.
</pre>
                  <br>
                  <br>

                  <p>Даже когда не происходит разбиения на слова,
                  операция подстановки команд может удалять завершающие
                  символы перевода строки.</p>
<pre class="PROGRAMLISTING"># cd "`pwd`"  # Должна выполняться всегда.
# Однако...

mkdir 'dir with trailing newline
'

cd 'dir with trailing newline
'

cd "`pwd`"  # Ошибка:
# bash: cd: /tmp/dir with trailing newline: No such file or directory

cd "$PWD"   # Выполняется без ошибки.





old_tty_setting=$(stty -g)   # Сохранить настройки терминала.
echo "Нажмите клавишу "
stty -icanon -echo           # Запретить "канонический" режим терминала.
                             # Также запрещает эхо-вывод.
key=$(dd bs=1 count=1 2&gt; /dev/null)   # Поймать нажатие на клавишу.
stty "$old_tty_setting"      # Восстановить настройки терминала.
echo "Количество нажатых клавиш = ${#key}."  # ${#variable} = количество символов в переменной $variable
#
# Нажмите любую клавишу, кроме RETURN, на экране появится "Количество нажатых клавиш = 1."
# Нажмите RETURN, и получите: "Количество нажатых клавиш = 0."
# Символ перевода строки будет "съеден" операцией подстановки команды.

Спасибо S.C.
</pre>
                  <br>
                  <br>
                </td>
              </tr>
            </tbody></table>
          </div>

          <div class="CAUTION">
            <table class="CAUTION" width="100%" border="0">
              <tbody><tr>
                <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                <td align="left" valign="top">
                  <p>При выводе значений переменных, полученных в
                  результате подстановки команд, командой <strong class="COMMAND">echo</strong>, без кавычек, символы
                  перевода строки будут удалены. Это может оказаться
                  неприятным сюрпризом.</p>
<pre class="PROGRAMLISTING">dir_listing=`ls -l`
echo $dir_listing     # без кавычек

# Вы наверно ожидали увидеть удобочитаемый список каталогов.

# Однако, вы получите:
# total 3 -rw-rw-r-- 1 bozo bozo 30 May 13 17:15 1.txt -rw-rw-r-- 1 bozo
# bozo 51 May 15 20:57 t2.sh -rwxr-xr-x 1 bozo bozo 217 Mar 5 21:13 wi.sh

# Символы перевода строки были заменены пробелами.


echo "$dir_listing"   # в кавычках
# -rw-rw-r--    1 bozo       30 May 13 17:15 1.txt
# -rw-rw-r--    1 bozo       51 May 15 20:57 t2.sh
# -rwxr-xr-x    1 bozo      217 Mar  5 21:13 wi.sh
</pre>
                  <br>
                  <br>
                </td>
              </tr>
            </tbody></table>
          </div>

          <p>Подстановка команд позволяет даже записывать в переменные
          содержимое целых файлов, с помощью <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IOREDIRREF">перенаправления</a> или команды <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CATREF">cat</a>.</p>
<pre class="PROGRAMLISTING">variable1=`&lt;file1`      # Записать в переменную  "variable1" содержимое файла "file1".
variable2=`cat file2`   # Записать в переменную "variable2" содержимое файла "file2".

#  Замечание 1:
#  Удаляются символы перевода строки.
#
#  Замечание 2:
#  В переменные можно записать даже управляющие символы.
</pre>
          <br>
          <br>
<pre class="PROGRAMLISTING">#  Выдержки из системного файла /etc/rc.d/rc.sysinit
#+ (Red Hat Linux)


if [ -f /fsckoptions ]; then
        fsckoptions=`cat /fsckoptions`
...
fi
#
#
if [ -e "/proc/ide/${disk[$device]}/media" ] ; then
             hdmedia=`cat /proc/ide/${disk[$device]}/media`
...
fi
#
#
if [ ! -n "`uname -r | grep -- "-"`" ]; then
       ktag="`cat /proc/version`"
...
fi
#
#
if [ $usb = "1" ]; then
    sleep 5
    mouseoutput=`cat /proc/bus/usb/devices 2&gt;/dev/null|grep -E "^I.*Cls=03.*Prot=02"`
    kbdoutput=`cat /proc/bus/usb/devices 2&gt;/dev/null|grep -E "^I.*Cls=03.*Prot=01"`
...
fi
</pre>
          <br>
          <br>

          <div class="CAUTION">
            <table class="CAUTION" width="100%" border="0">
              <tbody><tr>
                <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                <td align="left" valign="top">
                  <p>Не используйте переменные для хранения содержимого
                  текстовых файлов <span class="emphasis"><em class="EMPHASIS">большого</em></span> объема, без
                  веских на то оснований. Не записывайте в переменные
                  содержимое <span class="emphasis"><em class="EMPHASIS">бинарных</em></span> файлов, даже
                  шутки ради.</p>

                  <div class="EXAMPLE">
                    <a name="STUPSCR"></a>

                    <p><strong>Пример 14-1. Глупая выходка</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# stupid-script-tricks.sh: Люди! Будьте благоразумны!
# Из "Глупые выходки", том I.


dangerous_variable=`cat /boot/vmlinuz`   # Сжатое ядро Linux.

echo "длина строки \$dangerous_variable = ${#dangerous_variable}"
# длина строки $dangerous_variable = 794151
# ('wc -c /boot/vmlinuz' даст другой результат.)

# echo "$dangerous_variable"
# Даже не пробуйте раскомментарить эту строку! Это приведет к зависанию сценария.


#  Автор этого документа не знает, где можно было бы использовать
#+ запись содержимого двоичных файлов в переменные.

exit 0
</pre>
                  </div>

                  <p>Обратите внимание: в данной ситуации не возникает
                  ошибки <span class="emphasis"><em class="EMPHASIS">переполнения буфера</em></span>.
                  Этот пример показывает превосходство защищенности
                  интерпретирующих языков, таких как Bash, от ошибок
                  программиста, над компилирующими языками
                  программирования.</p>
                </td>
              </tr>
            </tbody></table>
          </div>

          <p>Подстановка команд, позволяет записать в переменную
          результаты выполнения <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FORLOOPREF1">цикла</a>. Ключевым моментом здесь
          является команда <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ECHOREF">echo</a>, в теле цикла.</p>

          <div class="EXAMPLE">
            <a name="CSUBLOOP"></a>

            <p><strong>Пример 14-2. Запись результатов выполнения цикла
            в переменную</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# csubloop.sh: Запись результатов выполнения цикла в переменную

variable1=`for i in 1 2 3 4 5
do
  echo -n "$i"                 #  Здесь 'echo' -- это ключевой момент
done`

echo "variable1 = $variable1"  # variable1 = 12345


i=0
variable2=`while [ "$i" -lt 10 ]
do
  echo -n "$i"                 # Опять же, команда 'echo' просто необходима.
  let "i += 1"                 # Увеличение на 1.
done`

echo "variable2 = $variable2"  # variable2 = 0123456789

exit 0
</pre>
          </div>

          <table class="SIDEBAR" border="1" cellpadding="5">
            <tbody><tr>
              <td>
                <div class="SIDEBAR">
                  <a name="AEN11497"></a>

                  <p>Подстановка команд позволяет существенно расширить
                  набор инструментальных средств, которыми располагает
                  Bash. Суть состоит в том, чтобы написать программу
                  или сценарий, которая выводит результаты своей работы
                  на <code class="FILENAME">stdout</code> (как это делает
                  подавляющее большинство утилит в UNIX) и записать
                  вывод от программы в переменную.</p>
<pre class="PROGRAMLISTING">#include &lt;stdio.h&gt;

/*  Программа на C "Hello, world."  */

int main()
{
  printf( "Hello, world." );
  return (0);
}
</pre>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>gcc -o hello hello.c</strong></code>
             
</pre>
                  <br>
                  <br>
<pre class="PROGRAMLISTING">#!/bin/bash
# hello.sh

greeting=`./hello`
echo $greeting
</pre>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>sh hello.sh</strong></code>
<code class="COMPUTEROUTPUT">Hello, world.</code>
               
</pre>
                  <br>
                  <br>
                </div>
              </td>
            </tr>
          </tbody></table>

          <div class="NOTE">
            <table class="NOTE" width="100%" border="0">
              <tbody><tr>
                <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                <td align="left" valign="top">
                  <p>Альтернативой обратным одиночным кавычкам,
                  используемым для подстановки команд, можно считать
                  такую форму записи: <strong class="COMMAND">$(COMMAND)</strong>.</p>
<pre class="PROGRAMLISTING">output=$(sed -n /"$1"/p $file)   # К примеру из "grp.sh".

# Запись в переменную содержимого текстового файла.
File_contents1=$(cat $file1)
File_contents2=$(&lt;$file2)        # Bash допускает и такую запись.
</pre>
                  <br>
                  <br>
                </td>
              </tr>
            </tbody></table>
          </div>

          <p>Примеры подстановки команд в сценариях:</p>

          <ol type="1">
            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BINGREP">Пример 10-7</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CASECMD">Пример 10-26</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SEEDINGRANDOM">Пример 9-26</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX57">Пример 12-2</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LOWERCASE">Пример 12-15</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GRP">Пример 12-12</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX53">Пример 12-39</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX24">Пример 10-13</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SYMLINKS">Пример 10-10</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#STRIPC">Пример 12-24</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REDIR4">Пример 16-7</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TREE">Пример A-19</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PIDID">Пример 27-1</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MONTHLYPMT">Пример 12-32</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BASE">Пример 12-33</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ALTBC">Пример 12-34</a></p>
            </li>
          </ol>
          <br>
          <br>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="ARITHEXP"></a>Глава 15. Арифметические
          подстановки</h1>

          <p><a name="ARITHEXPREF"></a>Арифметические подстановки -- это
          мощный инструмент, предназначенный для выполнения
          арифметических операций в сценариях. Перевод строки в
          числовое выражение производится с помощью <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BACKQUOTESREF">обратных одиночных кавычек</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DBLPARENS">двойных круглых скобок</a> или предложения
          <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LETREF">let</a>.</p>

          <div class="VARIABLELIST">
            <p><strong><a name="ARITHEXPVAR1"></a>Вариации</strong></p>

            <dl>
              <dt>Арифметические подстановки в обратных одиночных
              кавычках (часто используются совместно с командой <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXPRREF">expr</a>)</dt>

              <dd>
<pre class="PROGRAMLISTING">z=`expr $z + 3`            # Команда 'expr' вычисляет значение выражения.
</pre>
                <br>
                <br>
              </dd>

              <dt>Арифметические подстановки в двойных круглых скобках,
              и предложение <strong class="COMMAND">let</strong></dt>

              <dd>
                <p>В арифметических подстановках, обратные одиночные
                кавычки могут быть заменены на двойные круглые скобки
                <code class="USERINPUT"><strong>$((...))</strong></code> или
                очень удобной конструкцией, с применением предложения
                <strong class="COMMAND">let</strong>.</p>
<pre class="PROGRAMLISTING">z=$(($z+3))
# $((EXPRESSION)) -- это подстановка арифметического выражения.  #  Не путайте с
                                                                 #+ подстановкой команд.

let z=z+3
let "z += 3"  # Кавычки позволяют вставляьб пробелы и специальные операторы.
#  Оператор 'let' вычисляет арифметическое выражение,
#+ это не подстановка арифметического выражения.
</pre>
                Все вышеприведенные примеры эквивалентны. Вы можете
                использовать любую из этих форм записи <span class="QUOTE">"по своему вкусу"</span>. <br>
                <br>

                <p>Примеры арифметических подстановок в сценариях:</p>

                <ol type="1">
                  <li>
                    <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX45">Пример 12-6</a></p>
                  </li>

                  <li>
                    <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX25">Пример 10-14</a></p>
                  </li>

                  <li>
                    <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX66">Пример 25-1</a></p>
                  </li>

                  <li>
                    <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BUBBLE">Пример 25-6</a></p>
                  </li>

                  <li>
                    <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TREE">Пример A-19</a></p>
                  </li>
                </ol>
                <br>
                <br>
              </dd>
            </dl>
          </div>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="IO-REDIRECTION"></a>Глава 16. Перенаправление
          ввода/вывода</h1>

          <p><a name="IOREDIRREF"></a></p>

          <p>В системе по-умолчанию всегда открыты три <span class="QUOTE">"файла"</span> -- <code class="FILENAME">stdin</code> (клавиатура), <code class="FILENAME">stdout</code> (экран) и <code class="FILENAME">stderr</code> (вывод сообщений об ошибках на
          экран). Эти, и любые другие открытые файлы, могут быть
          перенапрвлены. В данном случае, термин
          "перенаправление" означает получить вывод из файла,
          команды, программы, сценария или даже отдельного блока в
          сценарии (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX8">Пример 3-1</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RPMCHECK">Пример 3-2</a>) и передать его на вход в
          другой файл, команду, программу или сценарий.</p>

          <p><a name="FDREF"></a>С каждым открытым файлом связан дескриптор
          файла. <a name="AEN11633" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN11633"><span class="footnote">[44]</span></a> Дескрипторы файлов <code class="FILENAME">stdin</code>, <code class="FILENAME">stdout</code> и <code class="FILENAME">stderr</code> -- 0, 1 и 2, соответственно.
          При открытии дополнительных файлов, дескрипторы с 3 по 9
          остаются незанятыми. Иногда дополнительные дескрипторы могут
          сослужить неплохую службу, временно сохраняя в себе ссылку на
          <code class="FILENAME">stdin</code>, <code class="FILENAME">stdout</code> или <code class="FILENAME">stderr</code>. <a name="AEN11642" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN11642"><span class="footnote">[45]</span></a> Это упрощает возврат
          дескрипторов в нормальное состояние после сложных манипуляций
          с перенаправлением и перестановками (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REDIR1">Пример 16-1</a>).</p>

          <p><a name="IOREDIRECTIONREF"></a></p>
<pre class="PROGRAMLISTING">   COMMAND_OUTPUT &gt;
      # Перенаправление stdout (вывода) в файл.
      # Если файл отсутствовал, то он создется, иначе -- перезаписывается.

      ls -lR &gt; dir-tree.list
      # Создает файл, содержащий список дерева каталогов.

   : &gt; filename
      # Операция &gt; усекает файл "filename" до нулевой длины.
      # Если до выполнения операции файла не существовало,
      # то создается новый файл с нулевой длиной (тот же эффект дает команда 'touch').
      # Символ : выступает здесь в роли местозаполнителя, не выводя ничего.

   &gt; filename
      # Операция &gt; усекает файл "filename" до нулевой длины.
      # Если до выполнения операции файла не существовало,
      # то создается новый файл с нулевой длиной (тот же эффект дает команда 'touch').
      # (тот же результат, что и выше -- ": &gt;", но этот вариант неработоспособен
      # в некоторых командных оболочках.)

   COMMAND_OUTPUT &gt;&gt;
      # Перенаправление stdout (вывода) в файл.
      # Создает новый файл, если он отсутствовал, иначе -- дописывает в конец файла.


      # Однострочные команды перенаправления
      # (затрагивают только ту строку, в которой они встречаются):
      # --------------------------------------------------------------------

   1&gt;filename
      # Перенаправление вывода (stdout) в файл "filename".
   1&gt;&gt;filename
      # Перенаправление вывода (stdout) в файл "filename", файл открывается в режиме добавления.
   2&gt;filename
      # Перенаправление stderr в файл "filename".
   2&gt;&gt;filename
      # Перенаправление stderr в файл "filename", файл открывается в режиме добавления.
   &amp;&gt;filename
      # Перенаправление stdout и stderr в файл "filename".

      #==============================================================================
      # Перенаправление stdout, только для одной строки.
      LOGFILE=script.log

      echo "Эта строка будет записана в файл \"$LOGFILE\"." 1&gt;$LOGFILE
      echo "Эта строка будет добавлена в конец файла \"$LOGFILE\"." 1&gt;&gt;$LOGFILE
      echo "Эта строка тоже будет добавлена в конец файла \"$LOGFILE\"." 1&gt;&gt;$LOGFILE
      echo "Эта строка будет выведена на экран и не попадет в файл \"$LOGFILE\"."
      # После каждой строки, сделанное перенаправление автоматически "сбрасывается".



      # Перенаправление stderr, только для одной строки.
      ERRORFILE=script.errors

      bad_command1 2&gt;$ERRORFILE       #  Сообщение об ошибке запишется в $ERRORFILE.
      bad_command2 2&gt;&gt;$ERRORFILE      #  Сообщение об ошибке добавится в конец $ERRORFILE.
      bad_command3                    #  Сообщение об ошибке будет выведено на stderr,
                                      #+ и не попадет в $ERRORFILE.
      # После каждой строки, сделанное перенаправление также автоматически "сбрасывается".
      #==============================================================================



   2&gt;&amp;1
      # Перенаправляется stderr на stdout.
      # Сообщения об ошибках передаются туда же, куда и стандартный вывод.

   i&gt;&amp;j
      # Перенаправляется файл с дескриптором <span class="emphasis"><em class="EMPHASIS">i</em></span> в <span class="emphasis"><em class="EMPHASIS">j</em></span>.
      # Вывод в файл с дескриптором <span class="emphasis"><em class="EMPHASIS">i</em></span> передается в файл с дескриптором <span class="emphasis"><em class="EMPHASIS">j</em></span>.

   &gt;&amp;j
      # Перенаправляется  файл с дескриптором <span class="emphasis"><em class="EMPHASIS">1</em></span> (stdout) в файл с дескриптором <span class="emphasis"><em class="EMPHASIS">j</em></span>.
      # Вывод на stdout передается в файл с дескриптором <span class="emphasis"><em class="EMPHASIS">j</em></span>.

   0&lt; FILENAME
    &lt; FILENAME
      # Ввод из файла.
      # Парная команде <span class="QUOTE">"&gt;"</span>, часто встречается в комбинации с ней.
      #
      # grep search-word &lt;filename


   [j]&lt;&gt;filename
      # Файл "filename" открывается на чтение и запись, и связывается с дескриптором "j".
      # Если "filename" отсутствует, то он создается.
      # Если дескриптор "j" не указан, то, по-умолчанию, бередся дескриптор 0, stdin.
      #
      # Как одно из применений этого -- запись в конкретную позицию в файле.
      echo 1234567890 &gt; File    # Записать строку в файл "File".
      exec 3&lt;&gt; File       # Открыть "File" и связать с дескриптором 3.
      read -n 4 &lt;&amp;3             # Прочитать 4 символа.
      echo -n . &gt;&amp;3             # Записать символ точки.
      exec 3&gt;&amp;-                 # Закрыть дескриптор 3.
      cat File                  # ==&gt; 1234.67890
      # Произвольный доступ, да и только!



   |
      # Конвейер (канал).
      # Универсальное средство для объединения команд в одну цепочку.
      # Похоже на <span class="QUOTE">"&gt;"</span>, но на самом деле -- более обширная.
      # Используется для объединения команд, сценариев, файлов и программ в одну цепочку (конвейер).
      cat *.txt | sort | uniq &gt; result-file
      # Содержимое всех файлов .txt сортируется, удаляются повторяющиеся строки,
      # результат сохраняется в файле <span class="QUOTE">"result-file"</span>.
</pre>

          <p>Операции перенаправления и/или конвейеры могут
          комбинироваться в одной командной строке.</p>
<pre class="PROGRAMLISTING">command &lt; input-file &gt; output-file

command1 | command2 | command3 &gt; output-file
</pre>
          См. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DERPM">Пример 12-23</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FIFO">Пример A-17</a>.<br>
          <br>

          <p>Допускается перенаправление нескольких потоков в один
          файл.</p>
<pre class="PROGRAMLISTING">ls -yz &gt;&gt; command.log 2&gt;&amp;1
# Сообщение о неверной опции "yz" в команде "ls" будет записано в файл "command.log".
# Поскольку stderr перенаправлен в файл.
</pre>
          <br>
          <br>

          <div class="VARIABLELIST">
            <p><strong><a name="CFD"></a>Закрытие дескрипторов файлов</strong></p>

            <dl>
              <dt><span class="TOKEN">n&lt;&amp;-</span></dt>

              <dd>
                <p>Закрыть дескриптор входного файла <code class="REPLACEABLE"><em>n</em></code>.</p>
              </dd>

              <dt><span class="TOKEN">0&lt;&amp;-</span>, <span class="TOKEN">&lt;&amp;-</span></dt>

              <dd>
                <p>Закрыть <code class="FILENAME">stdin</code>.</p>
              </dd>

              <dt><span class="TOKEN">n&gt;&amp;-</span></dt>

              <dd>
                <p>Закрыть дескриптор выходного файла <code class="REPLACEABLE"><em>n</em></code>.</p>
              </dd>

              <dt><span class="TOKEN">1&gt;&amp;-</span>, <span class="TOKEN">&gt;&amp;-</span></dt>

              <dd>
                <p>Закрыть <code class="FILENAME">stdout</code>.</p>
              </dd>
            </dl>
          </div>

          <p>Дочерние процессы наследуют дескрипторы открытых файлов.
          По этой причине и работают конвейеры. Чтобы предотвратить
          наследование дескрипторов -- закройте их перед запуском
          дочернего процесса.</p>
<pre class="PROGRAMLISTING"># В конвейер передается только stderr.

exec 3&gt;&amp;1                              # Сохранить текущее "состояние" stdout.
ls -l 2&gt;&amp;1 &gt;&amp;3 3&gt;&amp;- | grep bad 3&gt;&amp;-    # Закрыть дескр. 3 для 'grep' (но не для 'ls').
#              ^^^^   ^^^^
exec 3&gt;&amp;-                              # Теперь закрыть его для оставшейся части сценария.

# Спасибо S.C.
</pre>
          <br>
          <br>

          <p>Дополнительные сведения о перенаправлении ввода/вывода вы
          найдете в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IOREDIRINTRO">Приложение D</a>.</p>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="AEN11702"></a>16.1. С помощью команды <strong class="COMMAND">exec</strong></h2>

            <p>Команда <strong class="COMMAND">exec &lt;filename</strong> перенаправляет
            ввод со <code class="FILENAME">stdin</code> на файл. С этого момента весь
            ввод, вместо <code class="FILENAME">stdin</code> (обычно это клавиатура), будет
            производиться из этого файла. Это дает возможность читать
            содержимое файла, строку за строкой, и анализировать каждую
            введенную строку с помощью <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SEDREF">sed</a> и/или <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AWKREF">awk</a>.</p>

            <div class="EXAMPLE">
              <a name="REDIR1"></a>

              <p><strong>Пример 16-1. Перенаправление <code class="FILENAME">stdin</code> с помощью exec</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Перенаправление stdin с помощью 'exec'.


exec 6&lt;&amp;0          # Связать дескр. #6 со стандартным вводом (stdin).
                   # Сохраняя stdin.

exec &lt; data-file   # stdin заменяется файлом "data-file"

read a1            # Читается первая строка из "data-file".
read a2            # Читается вторая строка из "data-file."

echo
echo "Следующие строки были прочитаны из файла."
echo "-----------------------------------------"
echo $a1
echo $a2

echo; echo; echo

exec 0&lt;&amp;6 6&lt;&amp;-
#  Восстанавливается stdin из дескр. #6, где он был предварительно сохранен,
#+ и дескр. #6 закрывается ( 6&lt;&amp;- ) освобождая его для других процессов.
#
# &lt;&amp;6 6&lt;&amp;-    дает тот же результат.

echo -n "Введите строку  "
read b1  # Теперь функция "read", как и следовало ожидать, принимает данные с обычного stdin.
echo "Строка, принятая со stdin."
echo "--------------------------"
echo "b1 = $b1"

echo

exit 0
</pre>
            </div>

            <p>Аналогично, конструкция <strong class="COMMAND">exec &gt;filename</strong> перенаправляет
            вывод на <code class="FILENAME">stdout</code> в заданный файл. После этого,
            весь вывод от команд, который обычно направляется на <code class="FILENAME">stdout</code>, теперь выводится в этот
            файл.</p>

            <div class="EXAMPLE">
              <a name="REASSIGNSTDOUT"></a>

              <p><strong>Пример 16-2. Перенаправление <code class="FILENAME">stdout</code> с помощью exec</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# reassign-stdout.sh

LOGFILE=logfile.txt

exec 6&gt;&amp;1           # Связать дескр. #6 со stdout.
                    # Сохраняя stdout.

exec &gt; $LOGFILE     # stdout замещается файлом "logfile.txt".

# ----------------------------------------------------------- #
# Весь вывод от команд, в данном блоке, записывается в файл $LOGFILE.

echo -n "Logfile: "
date
echo "-------------------------------------"
echo

echo "Вывод команды \"ls -al\""
echo
ls -al
echo; echo
echo "Вывод команды \"df\""
echo
df

# ----------------------------------------------------------- #

exec 1&gt;&amp;6 6&gt;&amp;-      # Восстановить stdout и закрыть дескр. #6.

echo
echo "== stdout восстановлено в значение по-умолчанию == "
echo
ls -al
echo

exit 0
</pre>
            </div>

            <div class="EXAMPLE">
              <a name="UPPERCONV"></a>

              <p><strong>Пример 16-3. Одновременное перенаправление
              устройств, <code class="FILENAME">stdin</code> и <code class="FILENAME">stdout</code>, с помощью команды
              exec</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# upperconv.sh
# Преобразование символов во входном файле в верхний регистр.

E_FILE_ACCESS=70
E_WRONG_ARGS=71

if [ ! -r "$1" ]     # Файл доступен для чтения?
then
  echo "Невозможно прочитать из заданного файла!"
  echo "Порядок использования: $0 input-file output-file"
  exit $E_FILE_ACCESS
fi                   #  В случае, если входной файл ($1) не задан
                     #+ код завершения будет этим же.

if [ -z "$2" ]
then
  echo "Необходимо задать выходной файл."
  echo "Порядок использования: $0 input-file output-file"
  exit $E_WRONG_ARGS
fi


exec 4&lt;&amp;0
exec &lt; $1            # Назначить ввод из входного файла.

exec 7&gt;&amp;1
exec &gt; $2            # Назначить вывод в выходной файл.
                     # Предполагается, что выходной файл доступен для записи
                     # (добавить проверку?).

# -----------------------------------------------
    cat - | tr a-z A-Z   # Перевод в верхний регистр
#   ^^^^^                # Чтение со stdin.
#           ^^^^^^^^^^   # Запись в stdout.
# Однако, и stdin и stdout были перенаправлены.
# -----------------------------------------------

exec 1&gt;&amp;7 7&gt;&amp;-       # Восстановить stdout.
exec 0&lt;&amp;4 4&lt;&amp;-       # Восстановить stdin.

# После восстановления, следующая строка выводится на stdout, чего и следовало ожидать.
echo "Символы из \"$1\" преобразованы в верхний регистр, результат записан в \"$2\"."

exit 0
</pre>
            </div>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="REDIRCB"></a>16.2. Перенаправление для блоков
            кода</h2>

            <p><a name="REDIRREF"></a>Блоки кода, такие как циклы <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WHILELOOPREF">while</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#UNTILLOOPREF">until</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FORLOOPREF1">for</a>, условный оператор <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IFTHEN">if/then</a>, так же могут смешиваться с
            перенаправлением <code class="FILENAME">stdin</code>. Даже функции могут
            использовать эту форму перенаправления (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REALNAME">Пример 22-7</a>). Оператор
            перенаправления <span class="TOKEN">&lt;</span>, в таких случаях, ставится в
            конце блока.</p>

            <div class="EXAMPLE">
              <a name="REDIR2"></a>

              <p><strong>Пример 16-4. Перенаправление в цикл <span class="emphasis"><em class="EMPHASIS">while</em></span></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

if [ -z "$1" ]
then
  Filename=names.data       # По-умолчанию, если имя файла не задано.
else
  Filename=$1
fi
#  Конструкцию проверки выше, можно заменить следующей строкой (подстановка параметров):
#+ Filename=${1:-names.data}

count=0

echo

while [ "$name" != Smith ]  # Почему переменная $name взята в кавычки?
do
  read name                 # Чтение из $Filename, не со stdin.
  echo $name
  let "count += 1"
done &lt;"$Filename"           # Перенаправление на ввод из файла $Filename.
#    ^^^^^^^^^^^^

echo; echo "Имен прочитано: $count"; echo

#  Обратите внимание: в некоторых старых командных интерпретаторах,
#+ перенаправление в циклы приводит к запуску цикла в субоболочке (subshell).
#  Таким образом, переменная $count, по окончании цикла, будет содержать 0,
#  значение, записанное в нее до входа в цикл.
#  Bash и ksh стремятся избежать запуска субоболочки (subshell), если это возможно,
#+ так что этот сценарий, в этих оболочках, работает корректно.
#
# Спасибо Heiner Steven за это примечание.

exit 0
</pre>
            </div>

            <div class="EXAMPLE">
              <a name="REDIR2A"></a>

              <p><strong>Пример 16-5. Альтернативная форма
              перенаправления в цикле <span class="emphasis"><em class="EMPHASIS">while</em></span></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# Это альтернативный вариант предыдущего сценария.

#  Предложил: by Heiner Steven
#+ для случаев, когда циклы с перенаправлением
#+ запускаются в субоболочке, из-за чего переменные, устанавливаемые в цикле,
#+ не сохраняют свои значения по завершении цикла.


if [ -z "$1" ]
then
  Filename=names.data     # По-умолчанию, если имя файла не задано.
else
  Filename=$1
fi


exec 3&lt;&amp;0                 # Сохранить stdin в дескр. 3.
exec 0&lt;"$Filename"        # Перенаправить stdin.

count=0
echo


while [ "$name" != Smith ]
do
  read name               # Прочитать с перенаправленного stdin ($Filename).
  echo $name
  let "count += 1"
done &lt;"$Filename"         # Цикл читает из файла $Filename.
#    ^^^^^^^^^^^^


exec 0&lt;&amp;3                 # Восстановить stdin.
exec 3&lt;&amp;-                 # Закрыть временный дескриптор 3.

echo; echo "Имен прочитано: $count"; echo

exit 0
</pre>
            </div>

            <div class="EXAMPLE">
              <a name="REDIR3"></a>

              <p><strong>Пример 16-6. Перенаправление в цикл <span class="emphasis"><em class="EMPHASIS">until</em></span></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# То же самое, что и в предыдущем примере, только для цикла "until".

if [ -z "$1" ]
then
  Filename=names.data         # По-умолчанию, если файл не задан.
else
  Filename=$1
fi

# while [ "$name" != Smith ]
until [ "$name" = Smith ]     # Проверка != изменена на =.
do
  read name                   # Чтение из $Filename, не со stdin.
  echo $name
done &lt;"$Filename"             # Перенаправление на ввод из файла $Filename.
#    ^^^^^^^^^^^^

# Результаты получаются теми же, что и в случае с циклом "while", в предыдущем примере.

exit 0
</pre>
            </div>

            <div class="EXAMPLE">
              <a name="REDIR4"></a>

              <p><strong>Пример 16-7. Перенаправление в цикл <span class="emphasis"><em class="EMPHASIS">for</em></span></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

if [ -z "$1" ]
then
  Filename=names.data          # По-умолчанию, если файл не задан.
else
  Filename=$1
fi

line_count=`wc $Filename | awk '{ print $1 }'`
#           Число строк в файле.
#
#  Слишком запутано, тем не менее показывает
#+ возможность перенаправления stdin внутри цикла "for"...
#+ если вы достаточно умны.
#
# Более короткий вариант    line_count=$(wc &lt; "$Filename")


for name in `seq $line_count`  # "seq" выводит последовательность чисел.
# while [ "$name" != Smith ]   --   более запутанно, чем в случае с циклом "while"   --
do
  read name                    # Чтение из файла $Filename, не со stdin.
  echo $name
  if [ "$name" = Smith ]
  then
    break
  fi
done &lt;"$Filename"              # Перенаправление на ввод из файла $Filename.
#    ^^^^^^^^^^^^

exit 0
</pre>
            </div>

            <p>Предыдущий пример можно модифицировать так, чтобы
            перенаправить вывод из цикла.</p>

            <div class="EXAMPLE">
              <a name="REDIR4A"></a>

              <p><strong>Пример 16-8. Перенаправление устройств (<code class="FILENAME">stdin</code> и <code class="FILENAME">stdout</code>) в цикле <span class="emphasis"><em class="EMPHASIS">for</em></span></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

if [ -z "$1" ]
then
  Filename=names.data          # По-умолчанию, если файл не задан.
else
  Filename=$1
fi

Savefile=$Filename.new         # Имя файла, в котором сохраняются результаты.
FinalName=Jonah                # Имя, на котором завершается чтение.

line_count=`wc $Filename | awk '{ print $1 }'`  # Число строк в заданном файле.


for name in `seq $line_count`
do
  read name
  echo "$name"
  if [ "$name" = "$FinalName" ]
  then
    break
  fi
done &lt; "$Filename" &gt; "$Savefile"     # Перенаправление на ввод из файла $Filename,
#    ^^^^^^^^^^^^^^^^^^^^^^^^^^^       и сохранение результатов в файле.

exit 0
</pre>
            </div>

            <div class="EXAMPLE">
              <a name="REDIR5"></a>

              <p><strong>Пример 16-9. Перенаправление в конструкции
              <span class="emphasis"><em class="EMPHASIS">if/then</em></span></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

if [ -z "$1" ]
then
  Filename=names.data   # По-умолчанию, если файл не задан.
else
  Filename=$1
fi

TRUE=1

if [ "$TRUE" ]          # конструкции "if true" и "if :" тоже вполне допустимы.
then
 read name
 echo $name
fi &lt;"$Filename"
#  ^^^^^^^^^^^^

# Читает только первую строку из файла.

exit 0
</pre>
            </div>

            <div class="EXAMPLE">
              <a name="NAMESDATA"></a>

              <p><strong>Пример 16-10. Файл с именами <span class="QUOTE">"names.data"</span>, для
              примеров выше</strong></p>
<pre class="PROGRAMLISTING">Aristotle
Belisarius
Capablanca
Euler
Goethe
Hamurabi
Jonah
Laplace
Maroczy
Purcell
Schmidt
Semmelweiss
Smith
Turing
Venn
Wilson
Znosko-Borowski

#  Это файл с именами для примеров
#+ "redir2.sh", "redir3.sh", "redir4.sh", "redir4a.sh", "redir5.sh".
</pre>
            </div>

            <p>Перенаправление <code class="FILENAME">stdout</code> для блока кода, может
            использоваться для сохранения результатов работы этого
            блока в файл. См. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RPMCHECK">Пример 3-2</a>.</p>

            <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#HEREDOCREF">Встроенный документ</a> -- это особая
            форма перенаправления для блоков кода.</p>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="REDIRAPPS"></a>16.3. Область применения</h2>

            <p>Как один из вариантов грамотного применения
            перенаправления ввода/вывода, можно назвать разбор и
            "сшивание" вывода от команд (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#READREDIR">Пример 11-6</a>). Это позволяет
            создавать файлы отчетов и журналов регистрации событий.</p>

            <div class="EXAMPLE">
              <a name="LOGEVENTS"></a>

              <p><strong>Пример 16-11. Регистрация событий</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# logevents.sh, автор: Stephane Chazelas.

# Регистрация событий в файле.
# Сценарий должен запускаться с привилегиями root (что бы иметь право на запись в /var/log).

ROOT_UID=0     # Привилегии root имеет только пользователь с $UID = 0.
E_NOTROOT=67   # Код завершения, если не root.


if [ "$UID" -ne "$ROOT_UID" ]
then
  echo "Сценарий должен запускаться с привилегиями root."
  exit $E_NOTROOT
fi


FD_DEBUG1=3
FD_DEBUG2=4
FD_DEBUG3=5

# Раскомментарьте одну из двух строк, ниже, для активизации сценария.
# LOG_EVENTS=1
# LOG_VARS=1


log()  # Запись даты и времени в файл.
{
echo "$(date)  $*" &gt;&amp;7     # Добавляет в конец файла.
                              # См. ниже.
}



case $LOG_LEVEL in
 1) exec 3&gt;&amp;2         4&gt; /dev/null 5&gt; /dev/null;;
 2) exec 3&gt;&amp;2         4&gt;&amp;2         5&gt; /dev/null;;
 3) exec 3&gt;&amp;2         4&gt;&amp;2         5&gt;&amp;2;;
 *) exec 3&gt; /dev/null 4&gt; /dev/null 5&gt; /dev/null;;
esac

FD_LOGVARS=6
if [[ $LOG_VARS ]]
then exec 6&gt;&gt; /var/log/vars.log
else exec 6&gt; /dev/null               # Подавить вывод.
fi

FD_LOGEVENTS=7
if [[ $LOG_EVENTS ]]
then
  # then exec 7 &gt;(exec gawk '{print strftime(), $0}' &gt;&gt; /var/log/event.log)
  # Строка, выше, не работает в Bash, версии 2.04.
  exec 7&gt;&gt; /var/log/event.log        # Добавление в конец "event.log".
  log                                      # Записать дату и время.
else exec 7&gt; /dev/null                  # Подавить вывод.
fi

echo "DEBUG3: beginning" &gt;&amp;${FD_DEBUG3}

ls -l &gt;&amp;5 2&gt;&amp;4                       # command1 &gt;&amp;5 2&gt;&amp;4

echo "Done"                                # command2

echo "sending mail" &gt;&amp;${FD_LOGEVENTS}   # Написать "sending mail" в дескр. #7.


exit 0
</pre>
            </div>
          </div>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="HERE-DOCS"></a>Глава 17. Встроенные документы</h1>

          <p><a name="HEREDOCREF"></a></p>

          <p><em class="FIRSTTERM">Встроенный документ</em> (here document)
          является специальной формой <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IOREDIRREF">перенаправления ввода/вывода</a>, которая
          позволяет передать список команд интерактивной программе или
          команде, например <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTPREF">ftp</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TELNETREF">telnet</a> или <strong class="COMMAND">ex</strong>. Конец встроенного документа
          выделяется <span class="QUOTE">"строкой-ограничителем"</span>,
          которая задается с помощью специальной последовательности
          символов <span class="TOKEN">&lt;&lt;</span>. Эта последовательность --
          есть перенаправление вывода из файла в программу, напоминает
          конструкцию <code class="USERINPUT"><strong>interactive-program &lt;
          command-file</strong></code>, где <code class="FILENAME">command-file</code> содержит строки:</p>
<pre class="PROGRAMLISTING">command #1
command #2
...
</pre>
          <br>
          <br>

          <p>Сценарий, использующий <span class="QUOTE">"встроенный документ"</span> для тех
          же целей, может выглядеть примерно так:</p>
<pre class="PROGRAMLISTING">#!/bin/bash
interactive-program &lt;&lt;LimitString
command #1
command #2
...
LimitString
</pre>
          <br>
          <br>

          <p>В качестве строки-ограничителя должна выбираться такая
          последовательность символов, которая не будет встречаться в
          теле <span class="QUOTE">"встроенного документа"</span>.</p>

          <p>Обратите внимание: использование <span class="emphasis"><em class="EMPHASIS">встроенных документов</em></span> может
          иногда с успехом применяться и при работе с неинтерактивными
          командами и утилитами.</p>

          <div class="EXAMPLE">
            <a name="EX69"></a>

            <p><strong>Пример 17-1. dummyfile: Создание 2-х строчного
            файла-заготовки</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# Неинтерактивное редактирование файла с помощью 'vi'.
# Эмуляция 'sed'.

E_BADARGS=65

if [ -z "$1" ]
then
  echo "Порядок использования: `basename $0` filename"
  exit $E_BADARGS
fi

TARGETFILE=$1

# Вставить 2 строки в файл и сохранить.
#--------Начало встроенного документа-----------#
vi $TARGETFILE &lt;&lt;x23LimitStringx23
i
Это строка 1.
Это строка 2.
^[
ZZ
x23LimitStringx23
#----------Конец встроенного документа-----------#

#  Обратите внимание: ^[, выше -- это escape-символ
#+ Control-V &lt;Esc&gt;.

#  Bram Moolenaar указывает, что этот скрипт может не работать с 'vim',
#+ из-за возможных проблем взаимодействия с терминалом.

exit 0
</pre>
          </div>

          <p>Этот сценарий, с тем же эффектом, мог бы быть реализован,
          основываясь не на <strong class="COMMAND">vi</strong>, а на <strong class="COMMAND">ex</strong>. Встроенные документы,
          содержащие команды для <strong class="COMMAND">ex</strong>, стали настолько обычным делом,
          что их уже смело можно вынести в отдельную категорию -- <em class="FIRSTTERM">ex-сценарии</em>.</p>

          <div class="EXAMPLE">
            <a name="EX70"></a>

            <p><strong>Пример 17-2. broadcast: Передача сообщения всем,
            работающим в системе, пользователям</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

wall &lt;&lt;zzz23EndOfMessagezzz23
Пошлите, по электронной почте, ваш заказ на пиццу, системному администратору.
    (Добавьте дополнительный доллар, если вы желаете положить на пиццу анчоусы или грибы.)
# Внимание: строки комментария тоже будут переданы команде 'wall' как часть текста.
zzz23EndOfMessagezzz23

# Возможно, более эффективно это может быть сделано так:
#         wall &lt;message-file
# Однако, встроенный документ помогает сэкономить ваши силы и время.

exit 0
</pre>
          </div>

          <div class="EXAMPLE">
            <a name="EX71"></a>

            <p><strong>Пример 17-3. Вывод многострочных сообщений с
            помощью cat</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# Команда 'echo' прекрасно справляется с выводом однострочных сообщений,
# но иногда необходимо вывести несколько строк.
# Команда 'cat' и встроенный документ помогут вам в этом.

cat &lt;&lt;End-of-message
-------------------------------------
Это первая строка сообщения.
Это вторая строка сообщения.
Это третья строка сообщения.
Это четвертая строка сообщения.
Это последняя строка сообщения.
-------------------------------------
End-of-message

exit 0


#--------------------------------------------
# Команда "exit 0", выше, не позволить исполнить нижележащие строки.

# S.C. отмечает, что следующий код работает точно так же.
echo "-------------------------------------
Это первая строка сообщения.
Это вторая строка сообщения.
Это третья строка сообщения.
Это четвертая строка сообщения.
Это последняя строка сообщения.
-------------------------------------"
# Однако, в этом случае, двойные кавычки в теле сообщения, должны экранироваться.
</pre>
          </div>

          <p>Если строка-ограничитель встроенного документа начинается
          с символа <code class="OPTION">-</code> (<code class="USERINPUT"><strong>&lt;&lt;-LimitString</strong></code>), то
          это приводит к подавлению вывода символов табуляции (но не
          пробелов). Это может оказаться полезным при форматировании
          текста сценария для большей удобочитаемости.</p>

          <div class="EXAMPLE">
            <a name="EX71A"></a>

            <p><strong>Пример 17-4. Вывод многострочных сообщений с
            подавлением символов табуляции</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# То же, что и предыдущий сценарий, но...

#  Символ "-", начинающий строку-ограничитель встроенного документа: &lt;&lt;-
#  подавляет вывод символов табуляции, которые могут встречаться в теле документа,
#  но не пробелов.

cat &lt;&lt;-ENDOFMESSAGE
        Это первая строка сообщения.
        Это вторая строка сообщения.
        Это третья строка сообщения.
        Это четвертая строка сообщения.
        Это последняя строка сообщения.
ENDOFMESSAGE
# Текст, выводимый сценарием, будет смещен влево.
# Ведущие символы табуляции не будут выводиться.

# Вышеприведенные 5 строк текста "сообщения" начинаются с табуляции, а не с пробелов.


exit 0
</pre>
          </div>

          <p>Встроенные документы поддерживают подстановку команд и
          параметров. Что позволяет передавать различные параметры в
          тело встроенного документа.</p>

          <div class="EXAMPLE">
            <a name="EX71B"></a>

            <p><strong>Пример 17-5. Встроенные документы и подстановка
            параметров</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Вывод встроенного документа командой 'cat', с использованием подстановки параметров.

# Попробуйте запустить сценарий без аргументов,   ./scriptname
# Попробуйте запустить сценарий с одним аргументом,   ./scriptname Mortimer
# Попробуйте запустить сценарий с одним аргументом, из двух слов, в кавычках,
#                           ./scriptname "Mortimer Jones"

CMDLINEPARAM=1     # Минимальное число аргументов командной строки.

if [ $# -ge $CMDLINEPARAM ]
then
  NAME=$1          # Если аргументов больше одного,
                   # то рассматривается только первый.
else
  NAME="John Doe"  # По-умолчанию, если сценарий запущен без аргументов.
fi

RESPONDENT="автора этого сценария"


cat &lt;&lt;Endofmessage

Привет, $NAME!
Примите поздравления от $RESPONDENT.

# Этот комментарий тоже выводится (почему?).

Endofmessage

# Обратите внимание на то, что пустые строки тоже выводятся.

exit 0
</pre>
          </div>

          <p>Заключая строку-ограничитель в кавычки или экранируя ее,
          можно запретить подстановку параметров в теле встроенного
          документа.</p>

          <div class="EXAMPLE">
            <a name="EX71C"></a>

            <p><strong>Пример 17-6. Отключение подстановки
            параметров</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Вывод встроенного документа командой 'cat', с запретом подстановки параметров.

NAME="John Doe"
RESPONDENT="автора этого сценария"

cat &lt;&lt;'Endofmessage'

Привет, $NAME.
Примите поздравления от $RESPONDENT.

Endofmessage

#  Подстановка параметров не производится, если строка ограничитель
#  заключена в кавычки или экранирована.
#  Тот же эффект дают:
#  cat &lt;&lt;"Endofmessage"
#  cat &lt;&lt;\Endofmessage

exit 0
</pre>
          </div>

          <p>Еще один пример сценария, содержащего встроенный документ
          и подстановку параметров в его теле.</p>

          <div class="EXAMPLE">
            <a name="EX72"></a>

            <p><strong>Пример 17-7. Передача пары файлов во входящий
            каталог на <span class="QUOTE">"Sunsite"</span></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# upload.sh

# Передача пары файлов (Filename.lsm, Filename.tar.gz)
# на Sunsite (ibiblio.org).

E_ARGERROR=65

if [ -z "$1" ]
then
  echo "Порядок использования: `basename $0` filename"
  exit $E_ARGERROR
fi


Filename=`basename $1`           # Отсечь имя файла от пути к нему.

Server="ibiblio.org"
Directory="/incoming/Linux"
# Вообще, эти строки должны бы не "зашиваться" жестко в сценарий,
# а приниматься в виде аргумента из командной строки.

Password="your.e-mail.address"   # Измените на свой.

ftp -n $Server &lt;&lt;End-Of-Session
# Ключ -n запрещает автоматическую регистрацию (auto-logon)

user anonymous "$Password"
binary
bell                # "Звякнуть" после передачи каждого файла
cd $Directory
put "$Filename.lsm"
put "$Filename.tar.gz"
bye
End-Of-Session

exit 0
</pre>
          </div>

          <p>Встроенные документы могут передаваться на вход функции,
          находящейся в том же сценарии.</p>

          <div class="EXAMPLE">
            <a name="HF"></a>

            <p><strong>Пример 17-8. Встроенные документы и
            функции</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# here-function.sh

GetPersonalData ()
{
  read firstname
  read lastname
  read address
  read city
  read state
  read zipcode
} # Это немного напоминает интерактивную функцию, но...


# Передать ввод в функцию.
GetPersonalData &lt;&lt;RECORD001
Bozo
Bozeman
2726 Nondescript Dr.
Baltimore
MD
21226
RECORD001


echo
echo "$firstname $lastname"
echo "$address"
echo "$city, $state $zipcode"
echo

exit 0
</pre>
          </div>

          <p><a name="ANONHEREDOC0"></a></p>

          <p>Встроенный документ можно передать "пустой
          команде" <span class="TOKEN">:</span>. Такая конструкция, фактически,
          создает <span class="QUOTE">"анонимный"</span> встроенный
          документ.</p>

          <div class="EXAMPLE">
            <a name="ANONHEREDOC"></a>

            <p><strong>Пример 17-9. <span class="QUOTE">"Анонимный"</span> Встроенный
            Документ</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

: &lt;&lt;TESTVARIABLES
${HOSTNAME?}${USER?}${MAIL?}  # Если одна из переменных не определена, то выводится сообщение об ошибке.
TESTVARIABLES

exit 0
</pre>
          </div>

          <p><a name="CBLOCK1"></a></p>

          <div class="TIP">
            <table class="TIP" width="100%" border="0">
              <tbody><tr>
                <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/tip.gif" hspace="5" alt="Tip"></td>

                <td align="left" valign="top">
                  <p>Подобную технику можно использовать для создания
                  <span class="QUOTE">"блочных
                  комментариев"</span>.</p>
                </td>
              </tr>
            </tbody></table>
          </div>

          <div class="EXAMPLE">
            <a name="COMMENTBLOCK"></a>

            <p><strong>Пример 17-10. Блочный комментарий</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# commentblock.sh

: &lt;&lt; COMMENTBLOCK
echo "Эта строка не будет выведена."
Эта строка комментария не начинается с символа "#".
Это еще одна строка комментария, которая начинается не с символа "#".

&amp;*@!!++=
Эта строка не вызовет ошибки,
поскольку Bash проигнорирует ее.
COMMENTBLOCK

echo "Код завершения  \"COMMENTBLOCK\" = $?."   # 0
# Показывает, что ошибок не возникало.


#  Такая методика создания блочных комментариев
#+ может использоваться для комментирования блоков кода во время отладки.
#  Это экономит силы и время, т.к. не нужно втавлять символ "#" в начале каждой строки,
#+ а затем удалять их.

: &lt;&lt; DEBUGXXX
for file in *
do
 cat "$file"
done
DEBUGXXX

exit 0
</pre>
          </div>

          <div class="TIP">
            <table class="TIP" width="100%" border="0">
              <tbody><tr>
                <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/tip.gif" hspace="5" alt="Tip"></td>

                <td align="left" valign="top">
                  <p>Еще одно остроумное применение встроенных
                  документов -- встроенная справка к сценарию.</p>
                </td>
              </tr>
            </tbody></table>
          </div>

          <div class="EXAMPLE">
            <a name="SELFDOCUMENT"></a>

            <p><strong>Пример 17-11. Встроенная справка к
            сценарию</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# self-document.sh: сценарий со встроенной справкой
# Модификация сценария "colm.sh".

DOC_REQUEST=70

if [ "$1" = "-h"  -o "$1" = "--help" ]     # Request help.
then
  echo; echo "Порядок использования: $0 [directory-name]"; echo
  sed --silent -e '/DOCUMENTATIONXX$/,/^DOCUMENTATION/p' "$0" |
  sed -e '/DOCUMENTATIONXX/d'; exit $DOC_REQUEST; fi

: &lt;&lt; DOCUMENTATIONXX
Сценарий выводит сведения о заданном каталоге в виде таблице.
-------------------------------------------------------------
Сценарию необходимо передать имя каталога. Если каталог не
указан или он недоступен для чтения, то выводятся сведения
о текущем каталоге.

DOCUMENTATIONXX

if [ -z "$1" -o ! -r "$1" ]
then
  directory=.
else
  directory="$1"
fi

echo "Сведения о каталоге "$directory":"; echo
(printf "PERMISSIONS LINKS OWNER GROUP SIZE MONTH DAY HH:MM PROG-NAME\n" \
; ls -l "$directory" | sed 1d) | column -t

exit 0
</pre>
          </div>

          <div class="NOTE">
            <table class="NOTE" width="100%" border="0">
              <tbody><tr>
                <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                <td align="left" valign="top">
                  <p>Для встроенных документов, во время исполнения,
                  создаются временные файлы, но эти файлы удаляются
                  после открытия и недоступны для других процессов.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>bash -c 'lsof -a -p $$ -d0' &lt;&lt; EOF</strong></code>
<code class="PROMPT">&gt;</code> <code class="USERINPUT"><strong>EOF</strong></code>
<code class="COMPUTEROUTPUT">lsof    1213 bozo    0r   REG    3,5    0 30386 /tmp/t1213-0-sh (deleted)</code>
             
</pre>
                  <br>
                  <br>
                </td>
              </tr>
            </tbody></table>
          </div>

          <div class="CAUTION">
            <table class="CAUTION" width="100%" border="0">
              <tbody><tr>
                <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                <td align="left" valign="top">
                  <p>Некоторые утилиты не могут работать внутри <span class="emphasis"><em class="EMPHASIS">встроенных
                  документов</em></span>.</p>
                </td>
              </tr>
            </tbody></table>
          </div>

          <p>Если какая либо задача не может быть решена с помощью
          <span class="QUOTE">"встроенного документа"</span>, то
          вам следует попробовать язык сценариев <strong class="COMMAND">expect</strong>, который приспособлен для
          передачи параметров на вход интерактивных программ.</p>
        </div>
      </div>

      <div class="PART">
        <a name="PART4"></a>

        <div class="TITLEPAGE">
          <h1 class="TITLE">Часть 4. Материал повышенной сложности</h1>

          <div class="PARTINTRO">
            <a name="AEN11891"></a>

            <p>Итак, мы вплотную подошли к изучению очень сложных и
            необычных аспектов написания сценариев. В этой части мы
            попытаемся <span class="QUOTE">"сбросить покров тайны"</span> и
            <span class="emphasis"><em class="EMPHASIS">заглянуть за пределы известного нам
            мира</em></span> (представьте себе путешествие по
            территории, не отмеченной на карте).</p>
          </div>

          <div class="TOC">
            <dl>
              <dt><strong>Содержание</strong></dt>

              <dt>18. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REGEXP">Регулярные выражения</a></dt>

              <dd>
                <dl>
                  <dt>18.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN11904">Краткое введение в регулярные
                  выражения</a></dt>

                  <dt>18.2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GLOBBINGREF">Globbing -- Подстановка имен
                  файлов</a></dt>
                </dl>
              </dd>

              <dt>19. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SUBSHELLS">Подоболочки, или Subshells</a></dt>

              <dt>20. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RESTRICTED-SH">Ограниченный режим командной
              оболочки</a></dt>

              <dt>21. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PROCESS-SUB">Подстановка процессов</a></dt>

              <dt>22. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FUNCTIONS">Функции</a></dt>

              <dd>
                <dl>
                  <dt>22.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COMPLEXFUNCT">Сложные функции и сложности с
                  функциями</a></dt>

                  <dt>22.2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LOCALVAR">Локальные переменные</a></dt>

                  <dd>
                    <dl>
                      <dt>22.2.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LOCVARRECUR">Локальные переменные делают
                      возможной рекурсию.</a></dt>
                    </dl>
                  </dd>
                </dl>
              </dd>

              <dt>23. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ALIASES">Псевдонимы</a></dt>

              <dt>24. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LIST-CONS">Списки команд</a></dt>

              <dt>25. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ARRAYS">Массивы</a></dt>

              <dt>26. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FILES">Файлы</a></dt>

              <dt>27. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DEVPROC">/dev и /proc</a></dt>

              <dd>
                <dl>
                  <dt>27.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DEVREF1"><code class="FILENAME">/dev</code></a></dt>

                  <dt>27.2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PROCREF1"><code class="FILENAME">/proc</code></a></dt>
                </dl>
              </dd>

              <dt>28. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ZEROS">/dev/zero и /dev/null</a></dt>

              <dt>29. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DEBUGGING">Отладка сценариев</a></dt>

              <dt>30. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#OPTIONS">Необязательные параметры
              (ключи)</a></dt>

              <dt>31. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GOTCHAS">Широко распространенные ошибки</a></dt>

              <dt>32. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SCRSTYLE">Стиль программирования</a></dt>

              <dd>
                <dl>
                  <dt>32.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#UNOFFICIALST">Неофициальные рекомендации по
                  оформлению сценариев</a></dt>
                </dl>
              </dd>

              <dt>33. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MISCELLANY">Разное</a></dt>

              <dd>
                <dl>
                  <dt>33.1. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#INTANDNONINT">Интерактивный и неинтерактивный
                  режим работы</a></dt>

                  <dt>33.2. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WRAPPER">Сценарии-обертки</a></dt>

                  <dt>33.3. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TESTSANDCOMPARISONS">Операции сравнения:
                  Альтернативные решения</a></dt>

                  <dt>33.4. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RECURSIONSCT">Рекурсия</a></dt>

                  <dt>33.5. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COLORIZING"><span class="QUOTE">"Цветные"</span>
                  сценарии</a></dt>

                  <dt>33.6. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#OPTIMIZATIONS">Оптимизация</a></dt>

                  <dt>33.7. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ASSORTEDTIPS">Разные советы</a></dt>

                  <dt>33.8. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SECURITYISSUES">Проблемы
                  безопасности</a></dt>

                  <dt>33.9. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PORTABILITYISSUES">Проблемы
                  переносимости</a></dt>

                  <dt>33.10. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WINSCRIPT">Сценарии командной оболочки под
                  Windows</a></dt>
                </dl>
              </dd>

              <dt>34. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BASH2">Bash, версия 2</a></dt>
            </dl>
          </div>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="REGEXP"></a>Глава 18. Регулярные выражения</h1>

          <p><a name="REGEXREF"></a></p>

          <p>Для того, чтобы полностью реализовать потенциал командной
          оболочки, вам придется овладеть Регулярными Выражениями.
          Многие команды и утилиты, обычно используемые в сценариях,
          такие как <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GREPREF">grep</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXPRREF">expr</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SEDREF">sed</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AWKREF">awk</a>, используют Регулярные Выражения.</p>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="AEN11904"></a>18.1. Краткое введение в регулярные
            выражения</h2>

            <p>Выражение -- это строка символов. Символы, которые имеют
            особое назначение, называются <span class="emphasis"><em class="EMPHASIS">метасимволами</em></span>. Так, например,
            кавычки могут выделять прямую речь, т.е. быть <span class="emphasis"><em class="EMPHASIS">метасимволами</em></span> для строки,
            заключенной в эти кавычки. Регулярные выражения -- это
            набор символов и/или метасимволов, которые наделены особыми
            свойствами. <a name="AEN11909" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN11909"><span class="footnote">[46]</span></a></p>

            <p>Основное назначение регулярных выражений -- это поиск
            текста по шаблону и работа со строками.</p>

            <ul>
              <li>
                <p>Звездочка -- <span class="TOKEN">*</span> -- означает любое количество
                символов в строке, предшествующих
                "звездочке", <span class="emphasis"><em class="EMPHASIS">в том числе и нулевое число
                символов</em></span>.</p>

                <p>Выражение <span class="QUOTE">"1133*"</span> -- означает <code class="REPLACEABLE"><em>11 + один или более символов
                "3" + любые другие символы</em></code>: <code class="REPLACEABLE"><em>113</em></code>, <code class="REPLACEABLE"><em>1133</em></code>, <code class="REPLACEABLE"><em>113312</em></code>, и так
                далее.</p>
              </li>

              <li>
                <p><a name="REGEXDOT"></a>Точка -- <span class="TOKEN">.</span> -- означает не менее одного
                любого символа, за исключением символа перевода строки
                (\n). <a name="AEN11937" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN11937"><span class="footnote">[47]</span></a></p>

                <p>Выражение <span class="QUOTE">"13."</span> будет означать
                <code class="REPLACEABLE"><em>13 + по меньшей мере один
                любой символ (включая пробел)</em></code>: <code class="REPLACEABLE"><em>1133</em></code>, <code class="REPLACEABLE"><em>11333</em></code>, но не <code class="REPLACEABLE"><em>13</em></code> (отсутствуют
                дополнительные символы).</p>
              </li>

              <li>
                <p>Символ -- <span class="TOKEN">^</span> -- означает начало строки, но
                иногда, в зависимости от контекста, означает отрицание
                в регулярных выражениях.</p>
              </li>

              <li>
                <p><a name="DOLLARSIGNREF"></a></p>

                <p>Знак доллара -- <span class="TOKEN">$</span> -- в конце регулярного
                выражения соответствует концу строки.</p>

                <p>Выражение <span class="QUOTE">"^$"</span> соответствует
                пустой строке.</p>

                <div class="NOTE">
                  <table class="NOTE" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                      <td align="left" valign="top">
                        <p>Символы <span class="TOKEN">^</span> и <span class="TOKEN">$</span> иногда еще называют
                        <span class="emphasis"><em class="EMPHASIS">якорями</em></span>,
                        поскольку они означают, или закрепляют, позицию
                        в регулярных выражениях.</p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </li>

              <li>
                <p><a name="BRACKETSREF"></a></p>

                <p>Квадратные скобки -- <span class="TOKEN">[...]</span> -- предназначены для
                задания подмножества символов. Квадратные скобки,
                внутри регулярного выражения, считаются одним символом,
                который может принимать значения, перечисленные внутри
                этих скобок..</p>

                <p>Выражение <span class="QUOTE">"[xyz]"</span> --
                соответствует одному из символов <code class="REPLACEABLE"><em>x</em></code>, <code class="REPLACEABLE"><em>y</em></code> или <code class="REPLACEABLE"><em>z</em></code>.</p>

                <p>Выражение <span class="QUOTE">"[c-n]"</span> соответствует
                одному из символов в диапазоне от <code class="REPLACEABLE"><em>c</em></code> до <code class="REPLACEABLE"><em>n</em></code>, включительно.</p>

                <p>Выражение <span class="QUOTE">"[B-Pk-y]"</span>
                соответствует одному из символов в диапазоне от <code class="REPLACEABLE"><em>B</em></code> до <code class="REPLACEABLE"><em>P</em></code> или в диапазоне от
                <code class="REPLACEABLE"><em>k</em></code> до <code class="REPLACEABLE"><em>y</em></code>, включительно.</p>

                <p>Выражение <span class="QUOTE">"[a-z0-9]"</span>
                соответствует одному из символов латиницы в нижнем
                регистре или цифре.</p>

                <p>Выражение <span class="QUOTE">"[^b-d]"</span> соответствует
                любому символу, кроме символов из диапазона от <code class="REPLACEABLE"><em>b</em></code> до <code class="REPLACEABLE"><em>d</em></code>, включительно. В
                данном случае, метасимвол <span class="TOKEN">^</span> означает отрицание.</p>

                <p>Объединяя квадратные скобки в одну
                последовательность, можно задать шаблон искомого слова.
                Так, выражение <span class="QUOTE">"[Yy][Ee][Ss]"</span>
                соответствует словам <code class="REPLACEABLE"><em>yes</em></code>, <code class="REPLACEABLE"><em>Yes</em></code>, <code class="REPLACEABLE"><em>YES</em></code>, <code class="REPLACEABLE"><em>yEs</em></code> и так далее.
                Выражение <span class="QUOTE">"[0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9][0-9][0-9]"</span>
                определяет шаблон для поиска любого номера карточки
                социального страхования (для США).</p>
              </li>

              <li>
                <p>Обратный слэш -- <span class="TOKEN">\</span> -- служит для <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ESCP">экранирования</a> специальных символов,
                это означает, что экранированные символы должны
                интерпретироваться буквально, т.е. как простые
                символы.</p>

                <p>Комбинация <span class="QUOTE">"\$"</span> указывает на то,
                что символ <span class="QUOTE">"$"</span> трактуется как
                обычный символ, а не как признак конца строки в
                регулярных выражениях. Аналогично, комбинация <span class="QUOTE">"\\"</span> соответствует
                простому символу <span class="QUOTE">"\"</span>.</p>
              </li>

              <li>
                <p><a name="ANGLEBRAC"></a></p>

                <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ESCP">Экранированные</a> <span class="QUOTE">"угловые скобки"</span> --
                <span class="TOKEN">\&lt;...\&gt;</span> -- отмечают границы
                слова.</p>

                <p>Угловые скобки должны экранироваться, иначе они
                будут интерпретироваться как простые символы.</p>

                <p>Выражение <span class="QUOTE">"\&lt;the\&gt;"</span>
                соответствует слову <span class="QUOTE">"the"</span>, и не
                соответствует словам <span class="QUOTE">"them"</span>, <span class="QUOTE">"there"</span>, <span class="QUOTE">"other"</span> и т.п.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>cat textfile</strong></code>
<code class="COMPUTEROUTPUT">This is line 1, of which there is only one instance.
This is the only instance of line 2.
This is line 3, another line.
This is line 4.</code>


<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>grep 'the' textfile</strong></code>
<code class="COMPUTEROUTPUT">This is line 1, of which there is only one instance.
This is the only instance of line 2.
This is line 3, another line.</code>


<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>grep '\&lt;the\&gt;' textfile</strong></code>
<code class="COMPUTEROUTPUT">This is the only instance of line 2.</code>
             
</pre>
                <br>
                <br>
              </li>
            </ul>

            <ul>
              <li style="list-style-type: square">
                <div class="FORMALPARA">
                  <p><strong><a name="EXTREGEX"></a>Дополнительные
                  метасимволы.</strong> Использующиеся при работе с <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EGREPREF">egrep</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AWKREF">awk</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PERLREF">Perl</a></p>
                </div>
              </li>

              <li>
                <p><a name="QUEXREGEX"></a></p>

                <p>Знак вопроса -- <span class="TOKEN">?</span> -- означает, что предыдущий
                символ или регулярное выражение встречается 0 или 1
                раз. В основном используется для поиска одиночных
                символов.</p>
              </li>

              <li>
                <p><a name="PLUSREF"></a></p>

                <p>Знак "плюс" -- <span class="TOKEN">+</span> -- указывает на то, что
                предыдущий символ или выражение встречается 1 или более
                раз. Играет ту же роль, что и символ
                "звездочка" (<span class="TOKEN">*</span>), за исключением случая
                нулевого количества вхождений.</p>
<pre class="PROGRAMLISTING"># GNU версии sed и awk допускают использование "+",
# но его необходимо экранировать.

echo a111b | sed -ne '/a1\+b/p'
echo a111b | grep 'a1\+b'
echo a111b | gawk '/a1+b/'
# Все три варианта эквивалентны.

# Спасибо S.C.
</pre>
                <br>
                <br>
              </li>

              <li>
                <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ESCP">Экранированные</a> <span class="QUOTE">"фигурные скобки"</span> --
                <span class="TOKEN">\{ \}</span> -- задают число вхождений
                предыдущего выражения.</p>

                <p>Экранирование фигурных скобок -- обязательное
                условие, иначе они будут интерпретироваться как простые
                символы. Такой порядок использования, технически, не
                является частью основного набора правил построения
                регулярных выражений.</p>

                <p>Выражение <span class="QUOTE">"[0-9]\{5\}"</span> -- в
                точности соответствует подстроке из пяти десятичных
                цифр (символов из диапазона от 0 до 9,
                включительно).</p>

                <div class="NOTE">
                  <table class="NOTE" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                      <td align="left" valign="top">
                        <p>В <span class="QUOTE">"классической"</span>
                        (не совместимой с POSIX) версии <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AWKREF">awk</a>, фигурные скобки не
                        могут быть использованы. Однако, в <strong class="COMMAND">gawk</strong> предусмотрен
                        ключ <code class="OPTION">--re-interval</code>, который
                        позволяет использовать (неэкранированные)
                        фигурные скобки.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo 2222 | gawk --re-interval '/2{3}/'</strong></code>
<code class="COMPUTEROUTPUT">2222</code>
             
</pre>
                        <br>
                        <br>

                        <p>Язык программирования <strong class="COMMAND">Perl</strong> и некоторые
                        версии <strong class="COMMAND">egrep</strong> не требуют
                        экранирования фигурных скобок.</p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </li>

              <li>
                <p>Круглые скобки -- <strong class="COMMAND">( )</strong> -- предназначены для
                выделения групп регулярных выражений. Они полезны при
                использовании с оператором <span class="QUOTE">"<span class="TOKEN">|</span>"</span> и при <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXPRPAREN">извлечении подстроки</a> с помощью
                команды <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXPRREF">expr</a>.</p>
              </li>

              <li>
                <p>Вертикальная черта -- <strong class="COMMAND">|</strong> -- выполняет роль
                логического оператора <span class="QUOTE">"ИЛИ"</span> в регулярных
                выражениях и служит для задания набора альтернатив.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>egrep 're(a|e)d' misc.txt</strong></code>
<code class="COMPUTEROUTPUT">People who read seem to be better informed than those who do not.
The clarinet produces sound by the vibration of its reed.</code>
             
</pre>
                <br>
                <br>
              </li>
            </ul>

            <div class="NOTE">
              <table class="NOTE" width="100%" border="0">
                <tbody><tr>
                  <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                  <td align="left" valign="top">
                    <p>Некоторые версии <strong class="COMMAND">sed</strong>, <strong class="COMMAND">ed</strong> и <strong class="COMMAND">ex</strong> поддерживают
                    экранированные версии регулярных выражений,
                    описанных выше.</p>
                  </td>
                </tr>
              </tbody></table>
            </div>

            <ul>
              <li style="list-style-type: square">
                <div class="FORMALPARA">
                  <p><strong><a name="POSIXREF"></a>Классы символов POSIX.</strong>
                  <code class="USERINPUT"><strong>[:class:]</strong></code></p>
                </div>

                <p>Это альтернативный способ указания диапазона
                символов.</p>
              </li>

              <li>
                <p>Класс <code class="USERINPUT"><strong>[:alnum:]</strong></code> --
                соответствует алфавитным символам и цифрам.
                Эквивалентно выражению <code class="USERINPUT"><strong>[A-Za-z0-9]</strong></code>.</p>
              </li>

              <li>
                <p>Класс <code class="USERINPUT"><strong>[:alpha:]</strong></code> --
                соответствует символам алфавита. Эквивалентно выражению
                <code class="USERINPUT"><strong>[A-Za-z]</strong></code>.</p>
              </li>

              <li>
                <p>Класс <code class="USERINPUT"><strong>[:blank:]</strong></code> --
                соответствует символу пробела или символу
                табуляции.</p>
              </li>

              <li>
                <p>Класс <code class="USERINPUT"><strong>[:cntrl:]</strong></code> --
                соответствует управляющим символам (control
                characters).</p>
              </li>

              <li>
                <p>Класс <code class="USERINPUT"><strong>[:digit:]</strong></code> --
                соответствует набору десятичных цифр. Эквивалентно
                выражению <code class="USERINPUT"><strong>[0-9]</strong></code>.</p>
              </li>

              <li>
                <p>Класс <code class="USERINPUT"><strong>[:graph:]</strong></code>
                (печатаемые и псевдографические символы) --
                соответствует набору символов из диапазона ASCII 33 -
                126. Это то же самое, что и класс <code class="USERINPUT"><strong>[:print:]</strong></code>, за
                исключением символа пробела.</p>
              </li>

              <li>
                <p>Класс <code class="USERINPUT"><strong>[:lower:]</strong></code> --
                соответствует набору алфавитных символов в нижнем
                регистре. Эквивалентно выражению <code class="USERINPUT"><strong>[a-z]</strong></code>.</p>
              </li>

              <li>
                <p>Класс <code class="USERINPUT"><strong>[:print:]</strong></code>
                (печатаемые символы) -- соответствует набору символов
                из диапазона ASCII 32 - 126. По своему составу этот
                класс идентичен классу <code class="USERINPUT"><strong>[:graph:]</strong></code>,
                описанному выше, за исключением того, что в этом классе
                дополнительно присутствует символ пробела.</p>
              </li>

              <li>
                <p>Класс <code class="USERINPUT"><strong>[:space:]</strong></code> --
                соответствует пробельным символам (пробел и
                горизонтальная табуляция).</p>
              </li>

              <li>
                <p>Класс <code class="USERINPUT"><strong>[:upper:]</strong></code> --
                соответствует набору символов алфавита в верхнем
                регистре. Эквивалентно выражению <code class="USERINPUT"><strong>[A-Z]</strong></code>.</p>
              </li>

              <li>
                <p>Класс <code class="USERINPUT"><strong>[:xdigit:]</strong></code> --
                соответствует набору шестнадцатиричных цифр.
                Эквивалентно выражению <code class="USERINPUT"><strong>[0-9A-Fa-f]</strong></code>.</p>

                <div class="IMPORTANT">
                  <table class="IMPORTANT" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/important.gif" hspace="5" alt="Important"></td>

                      <td align="left" valign="top">
                        <p>Вообще, символьные классы POSIX требуют
                        заключения в кавычки или <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DBLBRACKETS">двойные квадратные
                        скобки</a> ([[ ]]).</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>grep [[:digit:]] test.file</strong></code>
<code class="COMPUTEROUTPUT">abc=723</code>
             
</pre>
                        <br>
                        <br>

                        <p>Эти символьные классы могут использоваться,
                        с некоторыми ограничениями, даже в операциях <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GLOBBINGREF">подстановки имен файлов
                        (globbing)</a>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>ls -l ?[[:digit:]][[:digit:]]?</strong></code>
<code class="COMPUTEROUTPUT">-rw-rw-r--    1 bozo  bozo         0 Aug 21 14:47 a33b</code>
             
</pre>
                        <br>
                        <br>

                        <p>Примеры использования символьных классов в
                        сценариях вы найдете в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX49">Пример 12-14</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LOWERCASE">Пример 12-15</a>.</p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </li>
            </ul>

            <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SEDREF">Sed</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AWKREF">awk</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PERLREF">Perl</a>, используемые в сценариях в
            качестве фильтров, могут принимать регулярные выражения в
            качестве входных аргументов. См. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BEHEAD">Пример A-13</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TREE">Пример A-19</a>.</p>

            <p>Книга "Sed &amp; Awk" (авторы Dougherty и
            Robbins) дает полное и ясное представление о регулярных
            выражениях (см. раздел <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BIBLIO"><em>Литература</em></a>).</p>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="GLOBBINGREF"></a>18.2. Globbing -- Подстановка имен
            файлов</h2>

            <p>Bash, сам по себе, не распознает регулярные выражения.
            Но в сценариях можно использовать команды и утилиты, такие
            как <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SEDREF">sed</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AWKREF">awk</a>, которые прекрасно справляются с
            обработкой регулярных выражений.</p>

            <p>Фактически, Bash может выполнять подстановку имен
            файлов, этот процесс называется <span class="QUOTE">"globbing"</span>, но при этом
            <span class="emphasis"><em class="EMPHASIS">не</em></span> используется стандартный
            набор регулярных выражений. Вместо этого, при выполнении
            подстановки имен файлов, производится распознавание и
            интерпретация шаблонных символов. В число интерпретируемых
            шаблонов входят символы <span class="TOKEN">*</span> и <span class="TOKEN">?</span>, списки символов в квадратных
            скобках и некоторые специальные символы (например <span class="TOKEN">^</span>, используемый для выполнения
            операции отрицания). Применение шаблонных символов имеет
            ряд важных ограничений. Например, если имена файлов
            начинаются с точки (например так: <code class="FILENAME">.bashrc</code>), то они не будут
            соответствовать шаблону, содержащему символ <code class="REPLACEABLE"><em>*</em></code>. <a name="AEN12295" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN12295"><span class="footnote">[48]</span></a> Аналогично, символ <code class="REPLACEABLE"><em>?</em></code> в операции подстановки
            имен файлов имеет иной смысл, нежели в регулярных
            выражениях.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>ls -l</strong></code>
<code class="COMPUTEROUTPUT">total 2
 -rw-rw-r--    1 bozo  bozo         0 Aug  6 18:42 a.1
 -rw-rw-r--    1 bozo  bozo         0 Aug  6 18:42 b.1
 -rw-rw-r--    1 bozo  bozo         0 Aug  6 18:42 c.1
 -rw-rw-r--    1 bozo  bozo       466 Aug  6 17:48 t2.sh
 -rw-rw-r--    1 bozo  bozo       758 Jul 30 09:02 test1.txt</code>

<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>ls -l t?.sh</strong></code>
<code class="COMPUTEROUTPUT">-rw-rw-r--    1 bozo  bozo       466 Aug  6 17:48 t2.sh</code>

<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>ls -l [ab]*</strong></code>
<code class="COMPUTEROUTPUT">-rw-rw-r--    1 bozo  bozo         0 Aug  6 18:42 a.1
 -rw-rw-r--    1 bozo  bozo         0 Aug  6 18:42 b.1</code>

<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>ls -l [a-c]*</strong></code>
<code class="COMPUTEROUTPUT">-rw-rw-r--    1 bozo  bozo         0 Aug  6 18:42 a.1
 -rw-rw-r--    1 bozo  bozo         0 Aug  6 18:42 b.1
 -rw-rw-r--    1 bozo  bozo         0 Aug  6 18:42 c.1</code>

<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>ls -l [^ab]*</strong></code>
<code class="COMPUTEROUTPUT">-rw-rw-r--    1 bozo  bozo         0 Aug  6 18:42 c.1
 -rw-rw-r--    1 bozo  bozo       466 Aug  6 17:48 t2.sh
 -rw-rw-r--    1 bozo  bozo       758 Jul 30 09:02 test1.txt</code>

<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>ls -l {b*,c*,*est*}</strong></code>
<code class="COMPUTEROUTPUT">-rw-rw-r--    1 bozo  bozo         0 Aug  6 18:42 b.1
 -rw-rw-r--    1 bozo  bozo         0 Aug  6 18:42 c.1
 -rw-rw-r--    1 bozo  bozo       758 Jul 30 09:02 test1.txt</code>


<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo *</strong></code>
<code class="COMPUTEROUTPUT">a.1 b.1 c.1 t2.sh test1.txt</code>

<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo t*</strong></code>
<code class="COMPUTEROUTPUT">t2.sh test1.txt</code>
             
</pre>
            <br>
            <br>

            <p>Даже команда <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ECHOREF">echo</a> может интерпретировать шаблонные
            символы в именах файлов.</p>

            <p>См. также <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LISTGLOB">Пример 10-4</a>.</p>
          </div>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="SUBSHELLS"></a>Глава 19. Подоболочки, или
          Subshells</h1>

          <p><a name="SUBSHELLSREF"></a></p>

          <p>Запуск сценария приводит к запуску дочернего командного
          интерпретатора. Который выполняет интерпретацию и исполнение
          списка команд, содержащихся в файле сценария, точно так же,
          как если бы они были введены из командной строки. Любой
          сценарий запускается как дочерний процесс <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FORKREF">родительской</a> командной оболочки, той
          самой, которая выводит перед вами строку приглашения к вводу
          на консоли или в окне xterm.</p>

          <p>Сценарий может, так же, запустить другой дочерний процесс,
          в своей подоболочке. Это позволяет сценариям распараллелить
          процесс обработки данных по нескольким задачам, исполняемым
          одновременно.</p>

          <div class="VARIABLELIST">
            <p><strong><a name="SUBSHELLPARENS1"></a>Список команд в круглых
            скобках</strong></p>

            <dl>
              <dt>( command1; command2; command3; ... )</dt>

              <dd>
                <p>Список команд, в круглых скобках, исполняется в
                подоболочке.</p>
              </dd>
            </dl>
          </div>

          <div class="NOTE">
            <table class="NOTE" width="100%" border="0">
              <tbody><tr>
                <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                <td align="left" valign="top">
                  <p><a name="PARVIS"></a>Значения переменных, определенных
                  в дочерней оболочке, <span class="emphasis"><em class="EMPHASIS">не</em></span> могут быть переданы
                  родительской оболочке. Они недоступны <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FORKREF">родительскому процессу</a>.
                  Фактически, они ведут себя как <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LOCALVAR">локальные переменные</a>.</p>
                </td>
              </tr>
            </tbody></table>
          </div>

          <div class="EXAMPLE">
            <a name="SUBSHELL"></a>

            <p><strong>Пример 19-1. Область видимости
            переменных</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# subshell.sh

echo

outer_variable=Outer

(
inner_variable=Inner
echo "Дочерний процесс, \"inner_variable\" = $inner_variable"
echo "Дочерний процесс, \"outer\" = $outer_variable"
)

echo

if [ -z "$inner_variable" ]
then
  echo "Переменная inner_variable не определена в родительской оболочке"
else
  echo "Переменная inner_variable определена в родительской оболочке"
fi

echo "Родительский процесс, \"inner_variable\" = $inner_variable"
# Переменная $inner_variable не будет определена
# потому, что переменные, определенные в дочернем процессе,
# ведут себя как "локальные переменные".

echo

exit 0
</pre>
          </div>

          <p>См. также <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SUBPIT">Пример 31-1</a>.</p>

          <p>+</p>

          <p>Смена текущего каталога в дочернем процессе (подоболочке)
          не влечет за собой смену текущего каталога в родительской
          оболочке.</p>

          <div class="EXAMPLE">
            <a name="ALLPROFS"></a>

            <p><strong>Пример 19-2. Личные настройки
            пользователей</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# allprofs.sh: вывод личных настроек (profiles) всех пользователей

# Автор: Heiner Steven
# С некоторыми изменениями, внесенными автором документа.

FILE=.bashrc  #  Файл настроек пользователя,
              #+ в оригинальном сценарии называется ".profile".

for home in `awk -F: '{print $6}' /etc/passwd`
do
  [ -d "$home" ] || continue    # Перейти к следующей итерации, если нет домашнего каталога.
  [ -r "$home" ] || continue    # Перейти к следующей итерации, если не доступен для чтения.
  (cd $home; [ -e $FILE ] &amp;&amp; less $FILE)
done

#  По завершении сценария -- нет теобходимости выполнять команду 'cd', чтобы вернуться в первоначальный каталог,
#+ поскольку 'cd $home' выполняется в подоболочке.

exit 0
</pre>
          </div>

          <p>Подоболочка может использоваться для задания <span class="QUOTE">"специфического окружения"</span>
          для группы команд.</p>
<pre class="PROGRAMLISTING">COMMAND1
COMMAND2
COMMAND3
(
  IFS=:
  PATH=/bin
  unset TERMINFO
  set -C
  shift 5
  COMMAND4
  COMMAND5
  exit 3 # Выход только из подоболочки.
)
# Изменение переменных окружения не коснется родительской оболочки.
COMMAND6
COMMAND7
</pre>
          Как вариант использования подоболочки -- проверка переменных.
          
<pre class="PROGRAMLISTING">if (set -u; : $variable) 2&gt; /dev/null
then
  echo "Переменная определена."
fi

# Можно сделать то же самое по другому: [[ ${variable-x} != x || ${variable-y} != y ]]
# или                                   [[ ${variable-x} != x$variable ]]
# или                                   [[ ${variable+x} = x ]])
</pre>
          Еще одно применение -- проверка файлов блокировки: 
<pre class="PROGRAMLISTING">if (set -C; : &gt; lock_file) 2&gt; /dev/null
then
  echo "Этот сценарий уже запущен другим пользователем."
  exit 65
fi

# Спасибо S.C.
</pre>
          <br>
          <br>

          <p>Процессы в подоболочках могут исполняться параллельно. Это
          позволяет разбить сложную задачу на несколько простых
          подзадач, выполняющих параллельную обработку информации.</p>

          <div class="EXAMPLE">
            <a name="PARALLEL-PROCESSES"></a>

            <p><strong>Пример 19-3. Запуск нескольких процессов в
            подоболочках</strong></p>
<pre class="PROGRAMLISTING">       (cat list1 list2 list3 | sort | uniq &gt; list123) &amp;
        (cat list4 list5 list6 | sort | uniq &gt; list456) &amp;
        # Слияние и сортировка двух списков производится одновременно.
        # Запуск в фоне гарантирует параллельное исполнение.
        #
        # Тот же эффект дает
        #   cat list1 list2 list3 | sort | uniq &gt; list123 &amp;
        #   cat list4 list5 list6 | sort | uniq &gt; list456 &amp;

        wait   # Ожидание завершения работы подоболочек.

        diff list123 list456
</pre>
          </div>

          <p>Перенаправление ввода/вывода в/из подоболочки производится
          оператором построения конвейера <span class="QUOTE">"|"</span>, например, <code class="USERINPUT"><strong>ls -al |
          (command)</strong></code>.</p>

          <div class="NOTE">
            <table class="NOTE" width="100%" border="0">
              <tbody><tr>
                <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                <td align="left" valign="top">
                  <p>Блок команд, заключенный в <code class="REPLACEABLE"><em>фигурные скобки</em></code> не
                  приводит к запуску дочерней подоболочки.</p>

                  <p>{ command1; command2; command3; ... }</p>
                </td>
              </tr>
            </tbody></table>
          </div>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="RESTRICTED-SH"></a>Глава 20. Ограниченный режим
          командной оболочки</h1>

          <div class="VARIABLELIST">
            <p><strong><a name="DISABLEDCOMMREF"></a>Команды, запрещенные в
            ограниченном режиме командной оболочки</strong></p>

            <dl>
              <dd>
                <div class="FORMALPARA">
                  <p>Запуск сценария или его части в <span class="emphasis"><em class="EMPHASIS">ограниченном</em></span> режиме,
                  приводит к наложению ограничений на использование
                  некоторых команд. Эта мера предназначена для
                  ограничения привилегий пользователя, запустившего
                  сценарий, и минимизации возможного ущерба системе,
                  который может нанести сценарий.</p>
                </div>
              </dd>

              <dd>
                <div class="FORMALPARA">
                  <p>В ограниченном режиме запрещена команда <code class="REPLACEABLE"><em>cd</em></code> -- смена
                  текщего каталога.</p>
                </div>
              </dd>

              <dd>
                <p>Запрещено изменять <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ENVREF">переменные окружения</a> <code class="REPLACEABLE"><em>$PATH</em></code>, <code class="REPLACEABLE"><em>$SHELL</em></code>, <code class="REPLACEABLE"><em>$BASH_ENV</em></code> и <code class="REPLACEABLE"><em>$ENV</em></code>.</p>
              </dd>

              <dd>
                <p>Заперщен доступ к переменной <code class="REPLACEABLE"><em>$SHELLOPTS</em></code>.</p>
              </dd>

              <dd>
                <p>Запрещено перенаправление вывода.</p>
              </dd>

              <dd>
                <p>Запрещен вызов утилит, в названии которых
                присутствует хотя бы один символ "слэш"
                (<span class="TOKEN">/</span>).</p>
              </dd>

              <dd>
                <p>Запрещен вызов команды <span class="emphasis"><em class="EMPHASIS">exec</em></span> для запуска другого
                процесса.</p>
              </dd>

              <dd>
                <p>Запрещен ряд других команд, которые могут
                использовать сценарий для выполнения непредусмотренных
                действий.</p>
              </dd>

              <dd>
                <p>Запрещен выход из ограниченного режима.</p>
              </dd>
            </dl>
          </div>

          <div class="EXAMPLE">
            <a name="RESTRICTED"></a>

            <p><strong>Пример 20-1. Запуск сценария в ограниченном
            режиме</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Если sha-bang задать в таком виде: "#!/bin/bash -r"
# то это приведет к включению ограниченного режима с момента запуска скрипта.

echo

echo "Смена каталога."
cd /usr/local
echo "Текущий каталог: `pwd`"
echo "Переход в домашний каталог."
cd
echo "Текущий каталог: `pwd`"
echo

# До сих пор сценарий исполнялся в обычном, неограниченном режиме.

set -r
# set --restricted    имеет тот же эффект.
echo "==&gt; Переход в ограниченный режим. &lt;=="

echo
echo

echo "Попытка сменить текущий каталог в ограниченном режиме."
cd ..
echo "Текущий каталог остался прежним: `pwd`"

echo
echo

echo "\$SHELL = $SHELL"
echo "Попытка смены командного интерпретатора в ограниченном режиме."
SHELL="/bin/ash"
echo
echo "\$SHELL= $SHELL"

echo
echo

echo "Попытка перенаправления вывода в ограниченном режиме."
ls -l /usr/bin &gt; bin.files
ls -l bin.files    # Попробуем найти файл, который пытались создать.

echo

exit 0
</pre>
          </div>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="PROCESS-SUB"></a>Глава 21. Подстановка процессов</h1>

          <p><a name="PROCESSSUBREF"></a><code class="REPLACEABLE"><em>Подстановка процессов</em></code> --
          это аналог <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COMMANDSUBREF">подстановки команд</a>. Операция
          подстановки команд записывает в переменную результат
          выполнения некоторой команды, например, <strong class="COMMAND">dir_contents=`ls -al`</strong> или <strong class="COMMAND">xref=$(grep word datafile)</strong>.
          Операция подстановки процессов передает вывод одного процесса
          на ввод другого (другими словами, передает результат
          выполнения одной команды -- другой).</p>

          <div class="VARIABLELIST">
            <p><strong><a name="COMMANDSPARENS1"></a>Шаблон подстановки
            команды</strong></p>

            <dl>
              <dt>Внутри круглых скобок</dt>

              <dd>
                <p><strong class="COMMAND">&gt;(command)</strong></p>

                <p><strong class="COMMAND">&lt;(command)</strong></p>

                <p>Таким образом инициируется подстановка процессов.
                Здесь, для передачи результата работы процесса в
                круглых скобках, используются файлы <code class="FILENAME">/dev/fd/&lt;n&gt;</code>. <a name="AEN12454" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN12454"><span class="footnote">[49]</span></a></p>

                <div class="NOTE">
                  <table class="NOTE" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                      <td align="left" valign="top">
                        <p>Между круглой скобкой и символом <span class="QUOTE">"&lt;"</span> или
                        <span class="QUOTE">"&gt;"</span>, не
                        должно быть пробелов, в противном случае это
                        вызовет сообщение об ошибке.</p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
              </dd>
            </dl>
          </div>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo &gt;(true)</strong></code>
<code class="COMPUTEROUTPUT">/dev/fd/63</code>

<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo &lt;(true)</strong></code>
<code class="COMPUTEROUTPUT">/dev/fd/63</code>
             
</pre>
          Bash создает канал с двумя <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FDREF">файловыми дескрипторами</a>, <code class="FILENAME">--fIn</code> и <code class="FILENAME">fOut--</code>. <code class="FILENAME">stdin</code> команды <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TRUEREF">true</a> присоединяется к <code class="FILENAME">fOut</code> (dup2(fOut, 0)), затем Bash
          передает <code class="FILENAME">/dev/fd/fIn</code> в качестве аргумента
          команде <strong class="COMMAND">echo</strong>. В системах, где отсутствуют
          файлы <code class="FILENAME">/dev/fd/&lt;n&gt;</code>, Bash может
          использовать временные файлы. (Спасибо S.C.)<br>
          <br>
<pre class="PROGRAMLISTING">cat &lt;(ls -l)
# То же самое, что и     ls -l | cat

sort -k 9 &lt;(ls -l /bin) &lt;(ls -l /usr/bin) &lt;(ls -l /usr/X11R6/bin)
# Список файлов в трех основных каталогах 'bin', отсортированный по именам файлов.
# Обратите внимание: на вход 'sort' поданы три самостоятельные команды.


diff &lt;(command1) &lt;(command2)    # Выдаст различия в выводе команд.

tar cf &gt;(bzip2 -c &gt; file.tar.bz2) $directory_name
# Вызовет "tar cf /dev/fd/?? $directory_name" и затем "bzip2 -c &gt; file.tar.bz2".
#
# Из-за особенностей, присущих некоторым системам, связанным с /dev/fd/&lt;n&gt;,
# канал между командами не обязательно должен быть именованным.
#
# Это можно сделать и так.
#
bzip2 -c &lt; pipe &gt; file.tar.bz2&amp;
tar cf pipe $directory_name
rm pipe
#        или
exec 3&gt;&amp;1
tar cf /dev/fd/4 $directory_name 4&gt;&amp;1 &gt;&amp;3 3&gt;&amp;- | bzip2 -c &gt; file.tar.bz2 3&gt;&amp;-
exec 3&gt;&amp;-


# Спасибо S.C.
</pre>
          <br>
          <br>

          <p>Ниже приводится еще один очень интересный пример
          использования подстановки процессов.</p>
<pre class="PROGRAMLISTING"># Фрагмент сценария из дистрибутива SuSE:

while read  des what mask iface; do
# Некоторые команды ...
done &lt; &lt;(route -n)


# Чтобы проверить это, попробуем вставить команду, выполняющую какие либо действия.
while read  des what mask iface; do
  echo $des $what $mask $iface
done &lt; &lt;(route -n)

# Вывод на экран:
# Kernel IP routing table
# Destination Gateway Genmask Flags Metric Ref Use Iface
# 127.0.0.0 0.0.0.0 255.0.0.0 U 0 0 0 lo


# Как указывает S.C. -- более простой для понимания эквивалент:
route -n |
  while read des what mask iface; do   # Переменные берут значения с устройства вывода конвейера (канала).
    echo $des $what $mask $iface
  done  #  На экран выводится то же самое, что и выше.
        #  Однако, Ulrich Gayer отметил, что ...
        #+ этот вариант запускает цикл while в подоболочке,
        #+ и поэтому переменные не видны за пределами цикла, после закрытия канала.
</pre>
          <br>
          <br>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="FUNCTIONS"></a>Глава 22. Функции</h1>

          <p><a name="FUNCTIONREF"></a></p>

          <p>Подобно <span class="QUOTE">"настоящим"</span> языкам
          программирования, Bash тоже имеет функции, хотя и в несколько
          ограниченном варианте. Функция -- это подпрограмма, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CODEBLOCKREF">блок кода</a> который реализует набор
          операций, своего рода <span class="QUOTE">"черный ящик"</span>,
          предназначенный для выполнения конкретной задачи. Функции
          могут использоваться везде, где имеются участки
          повторяющегося кода.</p>

          <p><strong class="COMMAND">function</strong> <code class="REPLACEABLE"><em>function_name</em></code> {<br>
           <code class="REPLACEABLE"><em>command</em></code>...<br>
           }<br>
          </p>
          или 

          <p><code class="REPLACEABLE"><em>function_name</em></code> () {<br>
           <code class="REPLACEABLE"><em>command</em></code>...<br>
           }<br>
          </p>
          <br>
          <br>

          <p>Вторая форма записи ближе к сердцу C-программистам (она же
          более переносимая).</p>

          <p>Как и в языке C, скобка, открывающая тело функции, может
          помещаться на следующей строке.</p>

          <p><code class="REPLACEABLE"><em>function_name</em></code> ()<br>
           {<br>
           <code class="REPLACEABLE"><em>command</em></code>...<br>
           }<br>
          </p>
          <br>
          <br>

          <p>Вызов функции осуществляется простым указанием ее имени в
          тексте сценария.</p>

          <div class="EXAMPLE">
            <a name="EX59"></a>

            <p><strong>Пример 22-1. Простая функция</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

funky ()
{
  echo "Это обычная функция."
} # Функция должна быть объявлена раньше, чем ее можно будет использовать.

  # Вызов функции.

funky

exit 0
</pre>
          </div>

          <p>Функция должна быть объявлена раньше, чем ее можно будет
          использовать. К сожалению, в Bash нет возможности <span class="QUOTE">"опережающего объявления"</span>
          функции, как например в C.</p>
<pre class="PROGRAMLISTING">f1
# Эта строка вызовет сообщение об ошибке, поскольку функция "f1" еще не определена.

declare -f f1      # Это не поможет.
f1                 # По прежнему -- сообщение об ошибке.

# Однако...


f1 ()
{
  echo "Вызов функции \"f2\" из функции \"f1\"."
  f2
}

f2 ()
{
  echo "Функция \"f2\"."
}

f1  #  Функция "f2", фактически, не вызывается выше этой строки,
    #+ хотя ссылка на нее встречается выше, до ее объявления.
    #  Это допускается.

    # Спасибо S.C.
</pre>
          <br>
          <br>

          <p>Допускается даже создание вложенных функций, хотя пользы
          от этого немного.</p>
<pre class="PROGRAMLISTING">f1 ()
{

  f2 () # вложенная
  {
    echo "Функция \"f2\", вложенная в \"f1\"."
  }

}

f2  #  Вызывает сообщение об ошибке.
    #  Даже "declare -f f2" не поможет.

echo

f1  #  Ничего не происходит, простой вызов "f1", не означает автоматический вызов "f2".
f2  #  Теперь все нормально, вызов "f2" не приводит к появлению ошибки,
    #+ поскольку функция "f2" была определена в процессе вызова "f1".

    # Спасибо S.C.
</pre>
          <br>
          <br>

          <p>Объявление функции может размещаться в самых неожиданных
          местах.</p>
<pre class="PROGRAMLISTING">ls -l | foo() { echo "foo"; }  # Допустимо, но бесполезно.



if [ "$USER" = bozo ]
then
  bozo_greet ()   # Объявление функции размещено в условном операторе.
  {
    echo "Привет, Bozo!"
  }
fi

bozo_greet        # Работает только у пользователя bozo, другие получат сообщение об ошибке.



# Нечто подобное можно использовать с определеной пользой для себя.
NO_EXIT=1   # Will enable function definition below.

[[ $NO_EXIT -eq 1 ]] &amp;&amp; exit() { true; }     # Определение функции в последовательности "И-список".
# Если $NO_EXIT равна 1, то объявляется "exit ()".
# Тем самым, функция "exit" подменяет встроенную команду "exit".

exit  # Вызывается функция "exit ()", а не встроенная команда "exit".

# Спасибо S.C.
</pre>
          <br>
          <br>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="COMPLEXFUNCT"></a>22.1. Сложные функции и сложности
            с функциями</h2>

            <p>Функции могут принимать входные аргументы и возвращать
            <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXITSTATUSREF">код завершения</a>.</p>
<pre class="PROGRAMLISTING">function_name $arg1 $arg2
</pre>

            <p>Доступ к входным аргументам, в функциях, производится
            посредством <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#POSPARAMREF">позиционных параметров</a>, т.е. <code class="VARNAME">$1</code>, <code class="VARNAME">$2</code> и так далее.</p>

            <div class="EXAMPLE">
              <a name="EX60"></a>

              <p><strong>Пример 22-2. Функция с
              аргументами</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Функции и аргументы

DEFAULT=default                             # Значение аргумента по-умолчанию.

func2 () {
   if [ -z "$1" ]                           # Длина аргумента #1 равна нулю?
   then
     echo "-Аргумент #1 имеет нулевую длину.-"  # Или аргумент не был передан функции.
   else
     echo "-Аргумент #1: \"$1\".-"
   fi

   variable=${1-$DEFAULT}                   #  Что делает
   echo "variable = $variable"              #+ показанная подстановка параметра?
                                            #  ---------------------------
                                            #  Она различает отсутствующий аргумент
                                            #+ от "пустого" аргумента.

   if [ "$2" ]
   then
     echo "-Аргумент #2: \"$2\".-"
   fi

   return 0
}

echo

echo "Вызов функции без аргументов."
func2
echo


echo "Вызов функции с \"пустым\" аргументом."
func2 ""
echo

echo "Вызов функции с неинициализированным аргументом."
func2 "$uninitialized_param"
echo

echo "Вызов функции с одним аргументом."
func2 first
echo

echo "Вызов функции с двумя аргументами."
func2 first second
echo

echo "Вызов функции с аргументами \"\" \"second\"."
func2 "" second       # Первый параметр "пустой"
echo                  # и второй параметр -- ASCII-строка.

exit 0
</pre>
            </div>

            <div class="IMPORTANT">
              <table class="IMPORTANT" width="100%" border="0">
                <tbody><tr>
                  <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/important.gif" hspace="5" alt="Important"></td>

                  <td align="left" valign="top">
                    <p>Команда <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SHIFTREF">shift</a> вполне применима и к
                    аргументам функций (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MULTIPLICATION">Пример 33-10</a>).</p>
                  </td>
                </tr>
              </tbody></table>
            </div>

            <div class="NOTE">
              <table class="NOTE" width="100%" border="0">
                <tbody><tr>
                  <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                  <td align="left" valign="top">
                    <p>В отличие от других языков программирования, в
                    сценариях на языке командной оболочке, в функции
                    передаются аргументы по значению. <a name="AEN12558" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN12558"><span class="footnote">[50]</span></a> Если имена
                    переменных (которые фактически являются
                    указателями) передаются функции в виде аргументов,
                    то они интерпретируются как обычные строки символов
                    и не могут быть разыменованы. <span class="emphasis"><em class="EMPHASIS">Функции интерпретируют свои
                    аргументы буквально.</em></span></p>
                  </td>
                </tr>
              </tbody></table>
            </div>

            <div class="VARIABLELIST">
              <p><strong><a name="EXITRETURN1"></a>Exit и Return</strong></p>

              <dl>
                <dt><strong class="COMMAND">код завершения</strong></dt>

                <dd>
                  <p>Функции возвращают значение в виде <em class="FIRSTTERM">кода завершения</em>. Код
                  завершения может быть задан явно, с помощью команды
                  <strong class="COMMAND">return</strong>, в противном случае
                  будет возвращен код завершения последней команды в
                  функции (<span class="RETURNVALUE">0</span> -- в случае успеха,
                  иначе -- ненулевой код ошибки). Код завершения в
                  сценарии может быть получен через переменную <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#XSTATVARREF">$?</a>.</p>
                </dd>

                <dt><strong class="COMMAND">return</strong></dt>

                <dd>
                  <p>Завершает исполнение функции. Команда <strong class="COMMAND">return</strong> <a name="AEN12587" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN12587"><span class="footnote">[51]</span></a> может иметь
                  необязательный аргумент типа <span class="emphasis"><em class="EMPHASIS">integer</em></span>, который
                  возвращается в вызывающий сценарий как <span class="QUOTE">"код завершения"</span>
                  функции, это значение так же записывается в
                  переменную <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#XSTATVARREF">$?</a>.</p>

                  <div class="EXAMPLE">
                    <a name="MAX"></a>

                    <p><strong>Пример 22-3. Наибольшее из двух
                    чисел</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# max.sh: Наибольшее из двух целых чисел.

E_PARAM_ERR=-198    # Если функции передано меньше двух параметров.
EQUAL=-199          # Возвращаемое значение, если числа равны.

max2 ()             # Возвращает наибольшее из двух чисел.
{                   # Внимание: сравниваемые числа должны быть меньше 257.
if [ -z "$2" ]
then
  return $E_PARAM_ERR
fi

if [ "$1" -eq "$2" ]
then
  return $EQUAL
else
  if [ "$1" -gt "$2" ]
  then
    return $1
  else
    return $2
  fi
fi
}

max2 33 34
return_val=$?

if [ "$return_val" -eq $E_PARAM_ERR ]
then
  echo "Функции должно быть передано два аргумента."
elif [ "$return_val" -eq $EQUAL ]
  then
    echo "Числа равны."
else
    echo "Наибольшее из двух чисел: $return_val."
fi


exit 0

#  Упражнение:
#  ---------------
#  Сделайте этот сценарий интерактивным,
#+ т.е. заставьте сценарий запрашивать числа для сравнения у пользователя (два числа).
</pre>
                  </div>

                  <div class="TIP">
                    <table class="TIP" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/tip.gif" hspace="5" alt="Tip"></td>

                        <td align="left" valign="top">
                          <p>Для случаев, когда функция должна
                          возвращать строку или массив, используйте
                          специальные переменные.</p>
<pre class="PROGRAMLISTING">count_lines_in_etc_passwd()
{
  [[ -r /etc/passwd ]] &amp;&amp; REPLY=$(echo $(wc -l &lt; /etc/passwd))
  # Если файл /etc/passwd доступен на чтение, то в переменную REPLY заносится число строк.
  # Возвращаются как количество строк, так и код завершения.
}

if count_lines_in_etc_passwd
then
  echo "В файле /etc/passwd найдено $REPLY строк."
else
  echo "Невозможно подсчитать число строк в файле /etc/passwd."
fi

# Спасибо S.C.
</pre>
                          <br>
                          <br>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>

                  <div class="EXAMPLE">
                    <a name="EX61"></a>

                    <p><strong>Пример 22-4. Преобразование чисел в
                    римскую форму записи</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# Преобразование чисел из арабской формы записи в римскую
# Диапазон: 0 - 200

# Расширение диапазона представляемых чисел и улучшение сценария
# оставляю вам, в качестве упражнения.

# Порядок использования: roman number-to-convert

LIMIT=200
E_ARG_ERR=65
E_OUT_OF_RANGE=66

if [ -z "$1" ]
then
  echo "Порядок использования: `basename $0` number-to-convert"
  exit $E_ARG_ERR
fi

num=$1
if [ "$num" -gt $LIMIT ]
then
  echo "Выход за границы диапазона!"
  exit $E_OUT_OF_RANGE
fi

to_roman ()   # Функция должна быть объявлена до того как она будет вызвана.
{
number=$1
factor=$2
rchar=$3
let "remainder = number - factor"
while [ "$remainder" -ge 0 ]
do
  echo -n $rchar
  let "number -= factor"
  let "remainder = number - factor"
done

return $number
       # Упражнение:
       # --------
       # Объясните -- как работает функция.
       # Подсказка: деление последовательным вычитанием.
}


to_roman $num 100 C
num=$?
to_roman $num 90 LXXXX
num=$?
to_roman $num 50 L
num=$?
to_roman $num 40 XL
num=$?
to_roman $num 10 X
num=$?
to_roman $num 9 IX
num=$?
to_roman $num 5 V
num=$?
to_roman $num 4 IV
num=$?
to_roman $num 1 I

echo

exit 0
</pre>
                  </div>

                  <p>См. также <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ISALPHA">Пример 10-28</a>.</p>

                  <div class="IMPORTANT">
                    <table class="IMPORTANT" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/important.gif" hspace="5" alt="Important"></td>

                        <td align="left" valign="top">
                          <p>Наибольшее положительное целое число,
                          которое может вернуть функция -- 255. Команда
                          <strong class="COMMAND">return</strong> очень тесно
                          связана с понятием <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXITSTATUSREF">код завершения</a>,
                          что объясняет это специфическое ограничение.
                          К счастью существуют <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RVT">различные способы</a>
                          преодоления этого ограничения.</p>

                          <div class="EXAMPLE">
                            <a name="RETURNTEST"></a>

                            <p><strong>Пример 22-5. Проверка
                            возможности возврата функциями больших
                            значений</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# return-test.sh

# Наибольшее целое число, которое может вернуть функция, не может превышать 256.

return_test ()         # Просто возвращает то, что ей передали.
{
  return $1
}

return_test 27         # o.k.
echo $?                # Возвращено число 27.

return_test 255        # o.k.
echo $?                # Возвращено число 255.

return_test 257        # Ошибка!
echo $?                # Возвращено число 1.

return_test -151896    # Как бы то ни было, но для больших отрицательных чисел проходит!
echo $?                # Возвращено число -151896.

exit 0
</pre>
                          </div>

                          <p>Как видно из примера, функции могут
                          возвращать большие отрицательные значения
                          (имеются ввиду -- большие по своему
                          абсолютному значению, прим. перев.).
                          Используя эту особенность, можно обыграть
                          возможность получения от функций большие
                          положительные значения.</p>

                          <p>Еще один способ -- использовать глобальные
                          переменные для хранения <span class="QUOTE">"возвращаемого
                          значения"</span>.</p>
<pre class="PROGRAMLISTING">Return_Val=   # Глобальная переменная, которая хранит значение, возвращаемое функцией.

alt_return_test ()
{
  fvar=$1
  Return_Val=$fvar
  return   # Возвратить 0 (успешное завершение).
}

alt_return_test 1
echo $?                                  # 0
echo "Функция вернула число $Return_Val" # 1

alt_return_test 255
echo "Функция вернула число $Return_Val" # 255

alt_return_test 257
echo "Функция вернула число $Return_Val" # 257

alt_return_test 25701
echo "Функция вернула число $Return_Val" #25701
</pre>
                          <br>
                          <br>

                          <div class="EXAMPLE">
                            <a name="MAX2"></a>

                            <p><strong>Пример 22-6. Сравнение двух
                            больших целых чисел</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# max2.sh: Наибольшее из двух БОЛЬШИХ целых чисел.

# Это модификация предыдущего примера "max.sh",
# которая позволяет выполнять сравнение больших целых чисел.

EQUAL=0             # Если числа равны.
MAXRETVAL=255       # Максимально возможное положительное число, которое может вернуть функция.
E_PARAM_ERR=-99999  # Код ошибки в параметрах.
E_NPARAM_ERR=99999  # "Нормализованный" код ошибки в параметрах.

max2 ()             # Возвращает наибольшее из двух больших целых чисел.
{
if [ -z "$2" ]
then
  return $E_PARAM_ERR
fi

if [ "$1" -eq "$2" ]
then
  return $EQUAL
else
  if [ "$1" -gt "$2" ]
  then
    retval=$1
  else
    retval=$2
  fi
fi

# -------------------------------------------------------------- #
# Следующие строки позволяют "обойти" ограничение
if [ "$retval" -gt "$MAXRETVAL" ]    # Если больше предельного значения,
then                                 # то
  let "retval = (( 0 - $retval ))"   # изменение знака числа.
  # (( 0 - $VALUE )) изменяет знак числа.
fi
# Функции имеют возможность возвращать большие *отрицательные* числа.
# -------------------------------------------------------------- #

return $retval
}

max2 33001 33997
return_val=$?

# -------------------------------------------------------------------------- #
if [ "$return_val" -lt 0 ]                  # Если число отрицательное,
then                                        # то
  let "return_val = (( 0 - $return_val ))"  # опять изменить его знак.
fi                                          # "Абсолютное значение" переменной $return_val.
# -------------------------------------------------------------------------- #


if [ "$return_val" -eq "$E_NPARAM_ERR" ]
then                   # Признак ошибки в параметрах, при выходе из функции так же поменял знак.
  echo "Ошибка: Недостаточно аргументов."
elif [ "$return_val" -eq "$EQUAL" ]
  then
    echo "Числа равны."
else
    echo "Наиболшее число: $return_val."
fi

exit 0
</pre>
                          </div>

                          <p>См. также <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DAYSBETWEEN">Пример A-8</a>.</p>

                          <p><code class="USERINPUT"><strong>Упражнение:</strong></code>
                          Используя только что полученные знания,
                          добавьте в предыдущий пример, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX61">преобразования чисел в римскую
                          форму записи</a>, возможность обрабатывать
                          большие числа.</p>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>
              </dl>
            </div>

            <div class="VARIABLELIST">
              <p><strong><a name="REDSTDINFUNC1"></a>Перенаправление</strong></p>

              <dl>
                <dt><code class="REPLACEABLE"><em>Перенаправление ввода для
                функций</em></code></dt>

                <dd>
                  <p>Функции -- суть есть <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CODEBLOCKREF">блок кода</a>, а это означает,
                  что устройство <code class="FILENAME">stdin</code> для функций может быть
                  переопределено (перенаправление stdin) (как в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX8">Пример 3-1</a>).</p>

                  <div class="EXAMPLE">
                    <a name="REALNAME"></a>

                    <p><strong>Пример 22-7. Настоящее имя
                    пользователя</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# По имени пользователя получить его "настоящее имя" из /etc/passwd.

ARGCOUNT=1  # Ожидается один аргумент.
E_WRONGARGS=65

file=/etc/passwd
pattern=$1

if [ $# -ne "$ARGCOUNT" ]
then
  echo "Порядок использования: `basename $0` USERNAME"
  exit $E_WRONGARGS
fi

file_excerpt ()  # Производит поиск в файле по заданному шаблону, выводит требуемую часть строки.
{
while read line
do
  echo "$line" | grep $1 | awk -F":" '{ print $5 }'  # Указывет awk использовать ":" как разделитель полей.
done
} &lt;$file  # Подменить stdin для функции.

file_excerpt $pattern

# Да, этот сценарий можно уменьшить до
#       grep PATTERN /etc/passwd | awk -F":" '{ print $5 }'
# или
#       awk -F: '/PATTERN/ {print $5}'
# или
#       awk -F: '($1 == "username") { print $5 }'
# Однако, это было бы не так поучительно.

exit 0
</pre>
                  </div>

                  <p>Ниже приводится альтернативный, и возможно менее
                  запутанный, способ перенаправления ввода для функций.
                  Он заключается в использовании перенаправления ввода
                  для блока кода, заключенного в фигурные скобки, в
                  пределах функции.</p>
<pre class="PROGRAMLISTING"># Вместо:
Function ()
{
 ...
 } &lt; file

# Попробуйте так:
Function ()
{
  {
    ...
   } &lt; file
}

# Похожий вариант,

Function ()  # Тоже работает.
{
  {
   echo $*
  } | tr a b
}

Function ()  # Этот вариант не работает.
{
  echo $*
} | tr a b   # Наличие вложенного блока кода -- обязательное условие.


# Спасибо S.C.
</pre>
                  <br>
                  <br>
                </dd>
              </dl>
            </div>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="LOCALVAR"></a>22.2. Локальные переменные</h2>

            <div class="VARIABLELIST">
              <p><strong><a name="LOCALSREF1"></a>Что такое <span class="QUOTE">"локальная"</span>
              переменная?</strong></p>

              <dl>
                <dt>локальные переменные</dt>

                <dd>
                  <p>Переменные, объявленные как <em class="FIRSTTERM">локальные</em>, имеют ограниченную
                  область видимости, и доступны только в пределах <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CODEBLOCKREF">блока</a>, в котором они были
                  объявлены. Для функций это означает, что локальная
                  переменная "видна" только в теле самой
                  функции.</p>

                  <div class="EXAMPLE">
                    <a name="EX62"></a>

                    <p><strong>Пример 22-8. Область видимости локальных
                    переменных</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

func ()
{
  local loc_var=23       # Объявление локальной переменной.
  echo
  echo "\"loc_var\" в функции = $loc_var"
  global_var=999         # Эта переменная не была объявлена локальной.
  echo "\"global_var\" в функции = $global_var"
}

func

# Проверим, "видна" ли локальная переменная за пределами функции.

echo
echo "\"loc_var\" за пределами функции = $loc_var"
                                      # "loc_var" за пределами функции =
                                      # Итак, $loc_var не видна в глобальном контексте.
echo "\"global_var\" за пределами функции = $global_var"
                                      # "global_var" за пределами функции = 999
                                      # $global_var имеет глобальную область видимости.
echo                                  

exit 0
</pre>
                  </div>

                  <div class="CAUTION">
                    <table class="CAUTION" width="90%" border="0">
                      <tbody><tr>
                        <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                        <td align="left" valign="top">
                          <p>Переменные, объявляемые в теле функции,
                          считаются необъявленными до тех пор, пока
                          функция не будет вызвана. Это касается <span class="emphasis"><em class="EMPHASIS">всех</em></span>
                          переменных.</p>
<pre class="PROGRAMLISTING">#!/bin/bash

func ()
{
global_var=37    #  Эта переменная будет считаться необъявленной
                 #+ до тех пор, пока функция не будет вызвана.
}                # КОНЕЦ ФУНКЦИИ

echo "global_var = $global_var"  # global_var =
                                 #  Функция "func" еще не была вызвана,
                                 #+ поэтому $global_var пока еще не "видна" здесь.

func
echo "global_var = $global_var"  # global_var = 37
                                 # Переменная была инициализирована в функции.
</pre>
                          <br>
                          <br>
                        </td>
                      </tr>
                    </tbody></table>
                  </div>
                </dd>
              </dl>
            </div>

            <div class="SECT2">
              <hr>

              <h3 class="SECT2"><a name="LOCVARRECUR"></a>22.2.1. Локальные переменные
              делают возможной рекурсию.</h3>

              <p>Хотя локальные переменные и допускают рекурсию, <a name="AEN12669" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN12669"><span class="footnote">[52]</span></a> но она сопряжена с
              большими накладными расходами и не рекомендуется для
              использования в сценариях. <a name="AEN12675" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN12675"><span class="footnote">[53]</span></a></p>

              <div class="EXAMPLE">
                <a name="EX63"></a>

                <p><strong>Пример 22-9. Использование локальных
                переменных при рекурсии</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

#               факториал
#               ---------


# Действительно ли bash допускает рекурсию?
# Да! Но...
# Нужно быть действительно дубинноголовым, чтобы использовать ее в сценариях
# на языке командной оболочки.


MAX_ARG=5
E_WRONG_ARGS=65
E_RANGE_ERR=66


if [ -z "$1" ]
then
  echo "Порядок использования: `basename $0` число"
  exit $E_WRONG_ARGS
fi

if [ "$1" -gt $MAX_ARG ]
then
  echo "Выход за верхний предел (максимально возможное число -- 5)."
  # Вернитесь к реальности.
  # Если вам захочется поднять верхнюю границу,
  # то перепишите эту программу на настоящем языке программирования.
  exit $E_RANGE_ERR
fi

fact ()
{
  local number=$1
  # Переменная "number" должна быть объявлена как локальная,
  # иначе результат будет неверный.
  if [ "$number" -eq 0 ]
  then
    factorial=1    # Факториал числа 0 = 1.
  else
    let "decrnum = number - 1"
    fact $decrnum  # Рекурсивный вызов функции.
    let "factorial = $number * $?"
  fi

  return $factorial
}

fact $1
echo "Факториал числа $1 = $?."

exit 0
</pre>
              </div>

              <p>Еще один пример использования рекурсии вы найдете в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PRIMES">Пример A-18</a>. Не забывайте, что
              рекурсия весьма ресурсоемкое удовольствие, к тому же она
              выполняется слишком медленно, поэтому не следует
              использовать ее в сценариях.</p>
            </div>
          </div>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="ALIASES"></a>Глава 23. Псевдонимы</h1>

          <p><a name="ALIASREF"></a></p>

          <p><span class="emphasis"><em class="EMPHASIS">Псевдонимы</em></span> в Bash -- это ни что
          иное, как "горячие клавиши", средство, позволяющее
          избежать набора длинных строк в командной строке. Если, к
          примеру, в файл <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FILESREF1"><code class="FILENAME">~/.bashrc</code></a> вставить строку <strong class="COMMAND">alias lm="ls -l | more"</strong>,
          то потом вы сможете экономить свои силы и время, набирая
          команду <code class="USERINPUT"><strong>lm</strong></code>, вместо более
          длинной <strong class="COMMAND">ls -l | more</strong>. Установив <strong class="COMMAND">alias rm="rm -i"</strong>
          (интерактивный режим удаления файлов), вы сможете избежать
          многих неприятностей, потому что сократится вероятность
          удаления важных файлов по неосторожности.</p>

          <p>Псевдонимы в сценариях могут иметь весьма ограниченную
          область применения. Было бы здорово, если бы псевдонимы имели
          функциональность, присущую макроопределениям в языке C, но, к
          сожалению, Bash не может "разворачивать" аргументы
          в теле псевдонима. <a name="AEN12698" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN12698"><span class="footnote">[54]</span></a> Кроме того, попытка
          обратиться к псевдониму, созданному внутри <span class="QUOTE">"составных конструкций"</span>,
          таких как <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IFTHEN">if/then</a>, циклы и функции, будет приводить
          к появлению ошибок. Практически всегда, действия, возлагаемые
          на псевдоним, более эффективно могут быть выполнены с помощью
          <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FUNCTIONREF">функций</a>.</p>

          <div class="EXAMPLE">
            <a name="AL"></a>

            <p><strong>Пример 23-1. Псевдонимы в сценарии</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

shopt -s expand_aliases
# Эта опция должна быть включена, иначе сценарий не сможет "разворачивать" псевдонимы.

alias ll="ls -l"
# В определении псевдонима можно использовать как одиночные ('), так и двойные (") кавычки.

echo "Попытка обращения к псевдониму \"ll\":"
ll /usr/X11R6/bin/mk*   #* Работает.

echo

directory=/usr/X11R6/bin/
prefix=mk*  # Определить -- не будет ли проблем с шаблонами.
echo "Переменные \"directory\" + \"prefix\" = $directory$prefix"
echo

alias lll="ls -l $directory$prefix"

echo "Попытка обращения к псевдониму \"lll\":"
lll         # Список всех файлов в /usr/X11R6/bin, чьи имена начинаются с mk.
# Псевдонимы могут работать с шаблонами.




TRUE=1

echo

if [ TRUE ]
then
  alias rr="ls -l"
  echo "Попытка обращения к псевдониму \"rr\", созданному внутри if/then:"
  rr /usr/X11R6/bin/mk*   #* В результате -- сообщение об ошибке!
  # К псевдонимам, созданным внутри составных инструкций, нельзя обратиться.
  echo "Однако, ранее созданный псевдоним остается работоспособным:"
  ll /usr/X11R6/bin/mk*
fi

echo

count=0
while [ $count -lt 3 ]
do
  alias rrr="ls -l"
  echo "Попытка обращения к псевдониму \"rrr\", созданному внутри цикла \"while\":"
  rrr /usr/X11R6/bin/mk*   #* Так же возникает ошибка.
                           #  alias.sh: line 57: rrr: command not found
  let count+=1
done

echo; echo

alias xyz='cat $0'   # Сценарий печатает себя самого.
                     # Обратите внимание на "строгие" кавычки.
xyz
#  Похоже работает,
#+ хотя документация Bash утверждает, что такой псевдоним не должен работать.
#
#  Steve Jacobson отметил, что
#+ параметр "$0" интерпретируется непосредственно, во время объявления псевдонима.

exit 0
</pre>
          </div>

          <p>Команда <strong class="COMMAND">unalias</strong> удаляет псевдоним,
          объявленный ранее .</p>

          <div class="EXAMPLE">
            <a name="UNAL"></a>

            <p><strong>Пример 23-2. unalias: Объявление и удаление
            псевдонимов</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

shopt -s expand_aliases  # Разрешить "разворачивание" псевдонимов.

alias llm='ls -al | more'
llm

echo

unalias llm              # Удалить псевдоним.
llm
# Сообщение об ошибке, т.к. команда 'llm' больше не распознается.

exit 0
</pre>
          </div>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>./unalias.sh</strong></code>
<code class="COMPUTEROUTPUT">total 6
drwxrwxr-x    2 bozo     bozo         3072 Feb  6 14:04 .
drwxr-xr-x   40 bozo     bozo         2048 Feb  6 14:04 ..
-rwxr-xr-x    1 bozo     bozo          199 Feb  6 14:04 unalias.sh

./unalias.sh: llm: command not found</code>
</pre>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="LIST-CONS"></a>Глава 24. Списки команд</h1>

          <p><a name="LISTCONSREF"></a></p>

          <p>Средством обработки последовательности из нескольких
          команд служат списки: <span class="QUOTE">"И-списки"</span> и <span class="QUOTE">"ИЛИ-списки"</span>. Они эффективно
          могут заменить сложную последовательность вложенных <strong class="COMMAND">if</strong>/<strong class="COMMAND">then</strong> или даже <strong class="COMMAND">case</strong>.</p>

          <div class="VARIABLELIST">
            <p><strong><a name="LCONS1"></a>Объединение команд в
            цепочки</strong></p>

            <dl>
              <dt>И-список</dt>

              <dd>
<pre class="PROGRAMLISTING">command-1 &amp;&amp; command-2 &amp;&amp; command-3 &amp;&amp; ... command-n
</pre>
                Каждая последующая команда, в таком списке, выполняется
                только тогда, когда предыдущая команда вернула код
                завершения <span class="RETURNVALUE">true</span> (ноль). Если
                какая-либо из команд возвращает <span class="RETURNVALUE">false</span> (не ноль), то
                исполнение списка команд в этом месте завершается, т.е.
                следующие далее команды не выполняются.<br>
                <br>

                <div class="EXAMPLE">
                  <a name="EX64"></a>

                  <p><strong>Пример 24-1. Проверка аргументов командной
                  строки с помощью <span class="QUOTE">"И-списка"</span></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# "И-список"

if [ ! -z "$1" ] &amp;&amp; echo "Аргумент #1 = $1" &amp;&amp; [ ! -z "$2" ] &amp;&amp; echo "Аргумент #2 = $2"
then
  echo "Сценарию передано не менее 2 аргументов."
  # Все команды в цепочке возвращают true.
else
  echo "Сценарию передано менее 2 аргументов."
  # Одна из команд в списке вернула false.
fi
# Обратите внимание: "if [ ! -z $1 ]" тоже работает, но, казалось бы эквивалентный вариант
#  if [ -n $1 ] -- нет. Однако, если добавить кавычки
#  if [ -n "$1" ] то все работает.  Будьте внимательны!
# Проверяемые переменные лучше всегда заключать в кавычки.


# То же самое, только без списка команд.
if [ ! -z "$1" ]
then
  echo "Аргумент #1 = $1"
fi
if [ ! -z "$2" ]
then
  echo "Аргумент #2 = $2"
  echo "Сценарию передано не менее 2 аргументов."
else
  echo "Сценарию передано менее 2 аргументов."
fi
# Получилось менее элегантно и длиннее, чем с использованием "И-списка".


exit 0
</pre>
                </div>

                <div class="EXAMPLE">
                  <a name="ANDLIST2"></a>

                  <p><strong>Пример 24-2. Еще один пример проверки
                  аргументов с помощью <span class="QUOTE">"И-списков"</span></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

ARGS=1        # Ожидаемое число аргументов.
E_BADARGS=65  # Код завершения, если число аргументов меньше ожидаемого.

test $# -ne $ARGS &amp;&amp; echo "Порядок использования: `basename $0` $ARGS аргумент(а)(ов)" &amp;&amp; exit $E_BADARGS
# Если проверка первого условия возвращает true (неверное число аргументов),
# то исполняется остальная часть строки, и сценарий завершается.

# Строка ниже выполняется только тогда, когда проверка выше не проходит.
# обратите внимание на условие "-ne" -- "не равно" (прим. перев.)
echo "Сценарию передано корректное число аргументов."

exit 0

# Проверьте код завершения сценария командой "echo $?".
</pre>
                </div>

                <p><a name="ANDDEFAULT"></a></p>

                <p>Конечно же, с помощью <span class="emphasis"><em class="EMPHASIS">И-списка</em></span> можно
                присваивать переменным значения по-умолчанию.</p>
<pre class="PROGRAMLISTING">arg1=$@       # В $arg1 записать аргументы командной строки.

[ -z "$arg1" ] &amp;&amp; arg1=DEFAULT
              # Записать DEFAULT, если аргументы командной строки отсутствуют.
</pre>
                <br>
                <br>
              </dd>

              <dt>ИЛИ-список</dt>

              <dd>
<pre class="PROGRAMLISTING">command-1 || command-2 || command-3 || ... command-n
</pre>
                Каждая последующая команда, в таком списке, выполняется
                только тогда, когда предыдущая команда вернула код
                завершения <span class="RETURNVALUE">false</span> (не ноль). Если
                какая-либо из команд возвращает <span class="RETURNVALUE">true</span> (ноль), то исполнение
                списка команд в этом месте завершается, т.е. следующие
                далее команды не выполняются. Очевидно, что <span class="QUOTE">"ИЛИ-списки"</span> имеют
                смысл обратный, по отношению к <span class="QUOTE">"И-спискам"</span><br>
                <br>

                <div class="EXAMPLE">
                  <a name="EX65"></a>

                  <p><strong>Пример 24-3. Комбинирование <span class="QUOTE">"ИЛИ-списков"</span> и <span class="QUOTE">"И-списков"</span></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

#  delete.sh, утилита удаления файлов.
#  Порядок использования: delete имя_файла

E_BADARGS=65

if [ -z "$1" ]
then
  echo "Порядок использования: `basename $0` имя_файла"
  exit $E_BADARGS  # Если не задано имя файла.
else
  file=$1          # Запомнить имя файла.
fi


[ ! -f "$file" ] &amp;&amp; echo "Файл \"$file\" не найден. \
Робкий отказ удаления несуществующего файла."
# И-СПИСОК, выдать сообщение об ошибке, если файл не существует.
# Обратите внимание: выводимое сообщение продолжается во второй строке,
# благодаря экранированию символа перевода строки.

[ ! -f "$file" ] || (rm -f $file; echo "Файл \"$file\" удален.")
# ИЛИ-СПИСОК, удаляет существующий файл.

# Обратите внимание на логические условия.
# И-СПИСОК отрабатывает по true, ИЛИ-СПИСОК -- по false.

exit 0
</pre>
                </div>
              </dd>
            </dl>
          </div>

          <div class="IMPORTANT">
            <table class="IMPORTANT" width="100%" border="0">
              <tbody><tr>
                <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/important.gif" hspace="5" alt="Important"></td>

                <td align="left" valign="top">
                  <p>Списки возвращают <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXITSTATUSREF">код завершения</a> последней
                  выполненной команды.</p>
                </td>
              </tr>
            </tbody></table>
          </div>

          <p>Комбинируя <span class="QUOTE">"И"</span> и <span class="QUOTE">"ИЛИ"</span> списки, легко
          "перемудрить" с логическими условиями, поэтому, в
          таких случаях может потребоваться детальная отладка.</p>
<pre class="PROGRAMLISTING">false &amp;&amp; true || echo false         # false

# Тот же результат дает
( false &amp;&amp; true ) || echo false     # false
# Но не эта комбинация
false &amp;&amp; ( true || echo false )     # (нет вывода на экран)

#  Обратите внимание на группировку и порядок вычисления условий -- слева-направо,
#+ поскольку логические операции "&amp;&amp;" и "||" имеют равный приоритет.

#  Если вы не уверены в своих действиях, то лучше избегать таких сложных конструкций.

#  Спасибо S.C.
</pre>
          <br>
          <br>

          <p>См. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DAYSBETWEEN">Пример A-8</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BROKENLINK">Пример 7-4</a>, иллюстрирующие
          использование <code class="USERINPUT"><strong>И/ИЛИ-списков</strong></code> для
          проверки переменных.</p>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="ARRAYS"></a>Глава 25. Массивы</h1>

          <p><a name="ARRAYREF"></a></p>

          <p>Новейшие версии Bash поддерживают одномерные массивы.
          Инициализация элементов массива может быть произведена в
          виде: <code class="USERINPUT"><strong>variable[xx]</strong></code>. Можно
          явно объявить массив в сценарии, с помощью директивы declare:
          <code class="USERINPUT"><strong>declare -a variable</strong></code>.
          Обращаться к отдельным элементам массива можно с помощью <em class="FIRSTTERM">фигурных скобок</em>, т.е.: <code class="USERINPUT"><strong>${variable[xx]}</strong></code>.</p>

          <div class="EXAMPLE">
            <a name="EX66"></a>

            <p><strong>Пример 25-1. Простой массив</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash


area[11]=23
area[13]=37
area[51]=UFOs

# Массивы не требуют, чтобы последовательность элементов в массиве была непрерывной.

# Некоторые элементы массива могут оставаться неинициализированными.
# "Дыркм" в массиве не являются ошибкой.


echo -n "area[11] = "
echo ${area[11]}    #  необходимы {фигурные скобки}

echo -n "area[13] = "
echo ${area[13]}

echo "содержимое area[51] = ${area[51]}."

# Обращение к неинициализированным элементам дает пустую строку.
echo -n "area[43] = "
echo ${area[43]}
echo "(элемент area[43] -- неинициализирован)"

echo

# Сумма двух элементов массива, записанная в третий элемент
area[5]=`expr ${area[11]} + ${area[13]}`
echo "area[5] = area[11] + area[13]"
echo -n "area[5] = "
echo ${area[5]}

area[6]=`expr ${area[11]} + ${area[51]}`
echo "area[6] = area[11] + area[51]"
echo -n "area[6] = "
echo ${area[6]}
# Эта попытка закончится неудачей, поскольку сложение целого числа со строкой не допускается.

echo; echo; echo

# -----------------------------------------------------------------
# Другой массив, "area2".
# И другой способ инициализации массива...
# array_name=( XXX YYY ZZZ ... )

area2=( ноль один два три четыре )

echo -n "area2[0] = "
echo ${area2[0]}
# Ага, индексация начинается с нуля (первый элемент массива имеет индекс [0], а не [1]).

echo -n "area2[1] = "
echo ${area2[1]}    # [1] -- второй элемент массива.
# -----------------------------------------------------------------

echo; echo; echo

# -----------------------------------------------
# Еще один массив, "area3".
# И еще один способ инициализации...
# array_name=([xx]=XXX [yy]=YYY ...)

area3=([17]=семнадцать [21]=двадцать_один)

echo -n "area3[17] = "
echo ${area3[17]}

echo -n "area3[21] = "
echo ${area3[21]}
# -----------------------------------------------

exit 0
</pre>
          </div>

          <div class="NOTE">
            <table class="NOTE" width="100%" border="0">
              <tbody><tr>
                <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                <td align="left" valign="top">
                  <p>Bash позволяет оперировать переменными, как
                  массивами, даже если они не были явно объявлены
                  таковыми.</p>
<pre class="PROGRAMLISTING">string=abcABC123ABCabc
echo ${string[@]}               # abcABC123ABCabc
echo ${string[*]}               # abcABC123ABCabc
echo ${string[0]}               # abcABC123ABCabc
echo ${string[1]}               # Ничего не выводится!
                                # Почему?
echo ${#string[@]}              # 1
                                # Количество элементов в массиве.

# Спасибо Michael Zick за этот пример.
</pre>
                  Эти примеры еще раз подтверждают <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BVUNTYPED">отсутствие контроля типов в
                  Bash</a>. <br>
                  <br>
                </td>
              </tr>
            </tbody></table>
          </div>

          <div class="EXAMPLE">
            <a name="POEM"></a>

            <p><strong>Пример 25-2. Форматирование
            стихотворения</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# poem.sh

# Строки из стихотворения (одна строфа).
Line[1]="Мой дядя самых честных правил,"
Line[2]="Когда не в шутку занемог;"
Line[3]="Он уважать себя заставил,"
Line[4]="И лучше выдумать не мог."
Line[5]="Его пример другим наука..."

# Атрибуты.
Attrib[1]=" А.С. Пушкин"
Attrib[2]="\"Евгений Онегин\""

for index in 1 2 3 4 5    # Пять строк.
do
  printf "     %s\n" "${Line[index]}"
done

for index in 1 2          # Две строки дополнительных атрибутов.
do
  printf "          %s\n" "${Attrib[index]}"
done

exit 0
</pre>
          </div>

          <p>При работе с отдельными элементами массива можно
          использовать специфический синтаксис, даже стандартные
          команды и операторы Bash адаптированы для работы с
          массивами.</p>
<pre class="PROGRAMLISTING">array=( ноль один два три четыре пять )

echo ${array[0]}       #  ноль
echo ${array:0}        #  ноль
                       #  Подстановка параметра -- первого элемента.
echo ${array:1}        #  оль
                       #  Подстановка параметра -- первого элемента,
                       #+ начиная с позиции #1 (со 2-го символа).

echo ${#array}         #  4
                       #  Длина первого элемента массива.



array2=( [0]="первый элемент" [1]="второй элемент" [3]="четвертый элемент" )

echo ${array2[0]}      # первый элемент
echo ${array2[1]}      # второй элемент
echo ${array2[2]}      #
                       # Элемент неинициализирован, поэтому на экран ничего не выводится.
echo ${array2[3]}      # четвертый элемент
</pre>
          <br>
          <br>

          <p>При работе с массивами, некоторые <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BUILTINREF">встроенные команды</a> Bash имеют
          несколько иной смысл. Например, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#UNSETREF">unset</a> -- удаляет отдельные элементы
          массива, или даже массив целиком.</p>

          <div class="EXAMPLE">
            <a name="EX67"></a>

            <p><strong>Пример 25-3. Некоторые специфичные особенности
            массивов</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

declare -a colors
# Допускается объявление массива без указания его размера.

echo "Введите ваши любимые цвета (разделяя их пробелами)."

read -a colors    # Введите хотя бы 3 цвета для демонстрации некоторых свойств массивов.
#  Специфический ключ команды 'read',
#+ позволяющий вводить несколько элементов массива.

echo

element_count=${#colors[@]}

# Получение количества элементов в массиве.
#     element_count=${#colors[*]} -- дает тот же результат.
#
#  Переменная "@" позволяет "разбивать" строку в кавычках на отдельные слова
#+ (выделяются слова, разделенные пробелами).

index=0

while [ "$index" -lt "$element_count" ]
do    # Список всех элементов в массиве.
  echo ${colors[$index]}
  let "index = $index + 1"
done
# Каждый элемент массива выводится в отдельной строке.
# Если этого не требуется, то используйте  echo -n "${colors[$index]} "
#
# Эквивалентный цикл "for":
#   for i in "${colors[@]}"
#   do
#     echo "$i"
#   done
# (Спасибо S.C.)

echo

# Еще один, более элегантный, способ вывода списка всех элементов массива.
  echo ${colors[@]}          # ${colors[*]} дает тот же результат.

echo

# Команда "unset" удаляет элементы из массива, или даже массив целиком.
unset colors[1]              # Удаление 2-го элемента массива.
                             # Тот же эффект дает команда   colors[1]=
echo  ${colors[@]}           # Список всех элементов массива -- 2-й элемент отсутствует.

unset colors                 # Удаление всего массива.
                             #  Тот же эффект имеют команды unset colors[*]
                             #+ и unset colors[@].
echo; echo -n "Массив цветов опустошен."
echo ${colors[@]}            # Список элементов массива пуст.

exit 0
</pre>
          </div>

          <p>Как видно из предыдущего примера, обращение к <strong class="COMMAND">${array_name[@]}</strong> или <strong class="COMMAND">${array_name[*]}</strong> относится ко <span class="emphasis"><em class="EMPHASIS">всем</em></span> элементам массива. Чтобы
          получить количество элементов массива, можно обратиться к
          <strong class="COMMAND">${#array_name[@]}</strong> или к <strong class="COMMAND">${#array_name[*]}</strong>. <strong class="COMMAND">${#array_name}</strong> -- это длина
          (количество символов) первого элемента массива, т.е. <strong class="COMMAND">${array_name[0]}</strong>.</p>

          <div class="EXAMPLE">
            <a name="EMPTYARRAY"></a>

            <p><strong>Пример 25-4. Пустые массивы и пустые
            элементы</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# empty-array.sh

#  Выражаю свою благодарность Stephane Chazelas за этот пример,
#+ и Michael Zick за его доработку.


# Пустой массив -- это не то же самое, что массив с пустыми элементами.

array0=( первый второй третий )
array1=( '' )   # "array1" имеет один пустой элемент.
array2=( )      # Массив "array2" не имеет ни одного элемента, т.е. пуст.

echo
ListArray()
{
echo
echo "Элементы массива array0:  ${array0[@]}"
echo "Элементы массива array1:  ${array1[@]}"
echo "Элементы массива array2:  ${array2[@]}"
echo
echo "Длина первого элемента массива array0 = ${#array0}"
echo "Длина первого элемента массива array1 = ${#array1}"
echo "Длина первого элемента массива array2 = ${#array2}"
echo
echo "Число элементов в массиве array0 = ${#array0[*]}"  # 3
echo "Число элементов в массиве array1 = ${#array1[*]}"  # 1  (сюрприз!)
echo "Число элементов в массиве array2 = ${#array2[*]}"  # 0
}

# ===================================================================

ListArray

# Попробуем добавить новые элементы в массивы

# Добавление новых элементов в массивы.
array0=( "${array0[@]}" "новый1" )
array1=( "${array1[@]}" "новый1" )
array2=( "${array2[@]}" "новый1" )

ListArray

# или
array0[${#array0[*]}]="новый2"
array1[${#array1[*]}]="новый2"
array2[${#array2[*]}]="новый2"

ListArray

# Теперь представим каждый массив как 'стек' ('stack')
# Команды выше, можно считать командами 'push' -- добавление нового значения на вершину стека
# 'Глубина' стека:
height=${#array2[@]}
echo
echo "Глубина стека array2 = $height"

# Команда 'pop' -- выталкивание элемента стека, находящегося на вершине:
unset array2[${#array2[@]}-1]   # Индексация массивов начинается с нуля
height=${#array2[@]}
echo
echo "POP"
echo "Глубина стека array2, после выталкивания = $height"

ListArray

# Вывести только 2-й и 3-й элементы массива array0
from=1          # Индексация массивов начинается с нуля
to=2              #
declare -a array3=( ${array0[@]:1:2} )
echo
echo "Элементы массива array3:  ${array3[@]}"

# Замена элементов по шаблону
declare -a array4=( ${array0[@]/второй/2-й} )
echo
echo "Элементы массива array4:  ${array4[@]}"

# Замена строк по шаблону
declare -a array5=( ${array0[@]//новый?/старый} )
echo
echo "Элементы массива array5:  ${array5[@]}"

# Надо лишь привыкнуть к такой записи...
declare -a array6=( ${array0[@]#*новый} )
echo # Это может вас несколько удивить
echo "Элементы массива array6:  ${array6[@]}"

declare -a array7=( ${array0[@]#новый1} )
echo # Теперь это вас уже не должно удивлять
echo "Элементы массива array7:  ${array7[@]}"

# Выглядить очень похоже на предыдущий вариант...
declare -a array8=( ${array0[@]/новый1/} )
echo
echo "Элементы массива array8:  ${array8[@]}"

#  Итак, что вы можете сказать обо всем этом?

#  Строковые операции выполняются последовательно, над каждым элементом
#+ в массиве var[@].
#  Таким образом, BASH поддерживает векторные операции
#  Если в результате операции получается пустая строка, то
#+ элемент массива "исчезает".

#  Вопрос: это относится к строкам в "строгих" или "мягких" кавычках?

zap='новый*'
declare -a array9=( ${array0[@]/$zap/} )
echo
echo "Элементы массива array9:  ${array9[@]}"

# "...А с платформы говорят: "Это город Ленинград!"..."
declare -a array10=( ${array0[@]#$zap} )
echo
echo "Элементы массива array10:  ${array10[@]}"

# Сравните массивы array7 и array10
# Сравните массивы array8 и array9

# Ответ: в "мягких" кавычках.

exit 0
</pre>
          </div>

          <p>Разница между <strong class="COMMAND">${array_name[@]}</strong> и <strong class="COMMAND">${array_name[*]}</strong> такая же, как
          между <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#APPREF">$@ и $*</a>. Эти свойства массивов широко
          применяются на практике.</p>
<pre class="PROGRAMLISTING"># Копирование массивов.
array2=( "${array1[@]}" )
# или
array2="${array1[@]}"

# Добавить элемент.
array=( "${array[@]}" "новый элемент" )
# или
array[${#array[*]}]="новый элемент"

# Спасибо S.C.
</pre>
          <br>
          <br>

          <div class="TIP">
            <table class="TIP" width="100%" border="0">
              <tbody><tr>
                <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/tip.gif" hspace="5" alt="Tip"></td>

                <td align="left" valign="top">
                  <p>Операция <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COMMANDSUBREF">подстановки команд</a> --
                  <strong class="COMMAND">array=( element1 element2 ...
                  elementN )</strong>, позволяет загружать содержимое
                  текстовых файлов в массивы.</p>
<pre class="PROGRAMLISTING">#!/bin/bash

filename=sample_file

#            cat sample_file
#
#            1 a b c
#            2 d e fg


declare -a array1

array1=( `cat "$filename" | tr '\n' ' '`)  # Загрузка содержимого файла
                                           # $filename в массив array1.
#         Вывод на stdout.
#                         с заменой символов перевода строки на пробелы.

echo ${array1[@]}            # список элементов массива.
#                              1 a b c 2 d e fg
#
#  Каждое "слово", в текстовом файле, отделяемое от других пробелами
#+ заносится в отдельный элемент массива.

element_count=${#array1[*]}
echo $element_count          # 8
</pre>
                  <br>
                  <br>
                </td>
              </tr>
            </tbody></table>
          </div>

          <div class="EXAMPLE">
            <a name="COPYARRAY"></a>

            <p><strong>Пример 25-5. Копирование и конкатенация
            массивов</strong></p>
<pre class="PROGRAMLISTING">#! /bin/bash
# CopyArray.sh
#
# Автор: Michael Zick.
# Используется с его разрешения.

#  "Принять из массива с заданным именем записать в массив с заданным именем"
#+ или "собственный Оператор Присваивания".


CpArray_Mac() {

# Оператор Присваивания

    echo -n 'eval '
    echo -n "$2"                    # Имя массива-результата
    echo -n '=( ${'
    echo -n "$1"                    # Имя исходного массива
    echo -n '[@]} )'

# Все это могло бы быть объединено в одну команду.
# Это лишь вопрос стиля.
}

declare -f CopyArray                # "Указатель" на функцию
CopyArray=CpArray_Mac               # Оператор Присваивания

Hype()
{

# Исходный массив с именем в $1.
# (Слить с массивом, содержащим "-- Настоящий Рок-н-Ролл".)
# Вернуть результат в массиве с именем $2.

    local -a TMP
    local -a hype=( -- Настоящий Рок-н-Ролл )

    $($CopyArray $1 TMP)
    TMP=( ${TMP[@]} ${hype[@]} )
    $($CopyArray TMP $2)
}

declare -a before=( Advanced Bash Scripting )
declare -a after

echo "Массив before = ${before[@]}"

Hype before after

echo "Массив after  = ${after[@]}"

# Еще?

echo "Что такое ${after[@]:4:2}?"

declare -a modest=( ${after[@]:2:1} ${after[@]:3:3} )
#                    ---- выделение подстроки ----

echo "Массив Modest = ${modest[@]}"

# А что в массиве 'before' ?

echo "Массив Before = ${before[@]}"

exit 0
</pre>
          </div>

          <p>--</p>

          <p>Массивы допускают перенос хорошо известных алгоритмов в
          сценарии на языке командной оболочки. Хорошо ли это -- решать
          вам.</p>

          <div class="EXAMPLE">
            <a name="BUBBLE"></a>

            <p><strong>Пример 25-6. Старая, добрая: <span class="emphasis"><em class="EMPHASIS">"Пузырьковая"
            сортировка</em></span></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# bubble.sh: "Пузырьковая" сортировка.

#  На каждом проходе по сортируемому массиву,
#+ сравниваются два смежных элемента, и, если необходимо, они меняются местами.
#  В конце первого прохода, самый "тяжелый" элемент "опускается" в конец массива.
#  В конце второго прохода, следующий по "тяжести" элемент занимает второе место снизу.
#  И так далее.
#  Каждый последующий проход требует на одно сравнение меньше предыдущего.
#  Поэтому вы должны заметить ускорение работы сценария на последних проходах.


exchange()
{
  # Поменять местами два элемента массива.
  local temp=${Countries[$1]} #  Временная переменная
  Countries[$1]=${Countries[$2]}
  Countries[$2]=$temp

  return
}

declare -a Countries  #  Объявление массива,
                      #+ необязательно, поскольку он явно инициализируется ниже.

#  Допустимо ли выполнять инициализацию массива в нескольки строках?
#  ДА!

Countries=(Нидерланды Украина Заир Турция Россия Йемен Сирия \
Бразилия Аргентина Никарагуа Япония Мексика Венесуэла Греция Англия \
Израиль Перу Канада Оман Дания Уэльс Франция Кения \
Занаду Катар Лихтенштейн Венгрия)

# "Занаду" -- это мифическое государство, где, согласно Coleridge,
#+ Kubla Khan построил величественный дворец.


clear                      # Очистка экрана.

echo "0: ${Countries[*]}"  # Список элементов несортированного массива.

number_of_elements=${#Countries[@]}
let "comparisons = $number_of_elements - 1"

count=1 # Номер прохода.

while [ "$comparisons" -gt 0 ]          # Начало внешнего цикла
do

  index=0  # Сбросить индекс перед началом каждого прохода.

  while [ "$index" -lt "$comparisons" ] # Начало внутреннего цикла
  do
    if [ ${Countries[$index]} \&gt; ${Countries[`expr $index + 1`]} ]
    #  Если элементы стоят не по порядку...
    #  Оператор \&gt; выполняет сравнение ASCII-строк
    #+ внутри одиночных квадратных скобок.

    #  if [[ ${Countries[$index]} &gt; ${Countries[`expr $index + 1`]} ]]
    #+ дает тот же результат.
    then
      exchange $index `expr $index + 1`  # Поменять местами.
    fi
    let "index += 1"
  done # Конец внутреннего цикла


let "comparisons -= 1" #  Поскольку самый "тяжелый" элемент уже "опустился" на дно,
                       #+ то на каждом последующем проходе нужно выполнять на одно сравнение меньше.

echo
echo "$count: ${Countries[@]}"  # Вывести содержимое массива после каждого прохода.
echo
let "count += 1"                # Увеличить счетчик проходов.

done                            # Конец внешнего цикла

exit 0
</pre>
          </div>

          <p>--</p>

          <p>Можно ли вложить один массив в другой?</p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Вложенный массив.

# Автор: Michael Zick.

AnArray=( $(ls --inode --ignore-backups --almost-all \
        --directory --full-time --color=none --time=status \
        --sort=time -l ${PWD} ) )  # Команды и опции.

# Пробелы важны . . .

SubArray=( ${AnArray[@]:11:1}  ${AnArray[@]:6:5} )
# Массив имеет два элемента, каждый из которых, в свою очередь, является массивом.

echo "Текущий каталог и дата последнего изменения:"
echo "${SubArray[@]}"

exit 0
</pre>
          <br>
          <br>

          <p>--</p>

          <p>Вложенные массивы, в комбинации с <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#VARREFNEW">косвенными ссылками</a>, предоставляют в
          распоряжение программиста ряд замечательных возможностей</p>

          <div class="EXAMPLE">
            <a name="EMBARR"></a>

            <p><strong>Пример 25-7. Вложенные массивы и косвенные
            ссылки</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# embedded-arrays.sh
# Вложенные массивы и косвенные ссылки.

# Автор: Dennis Leeuw.
# Используется с его разрешения.
# Дополнен автором документа.


ARRAY1=(
        VAR1_1=value11
        VAR1_2=value12
        VAR1_3=value13
)

ARRAY2=(
        VARIABLE="test"
        STRING="VAR1=value1 VAR2=value2 VAR3=value3"
        ARRAY21=${ARRAY1[*]}
)       # Вложение массива ARRAY1 в массив ARRAY2.

function print () {
        OLD_IFS="$IFS"
        IFS=$'\n'       #  Вывод каждого элемента массива
                        #+ в отдельной строке.
        TEST1="ARRAY2[*]"
        local ${!TEST1} # Посмотрите, что произойдет, если убрать эту строку.
        #  Косвенная ссылка.
        #  Позволяет получить доступ к компонентам $TEST1
        #+ в этой функции.


        #  Посмотрим, что получилось.
        echo
        echo "\$TEST1 = $TEST1"       #  Просто имя переменной.
        echo; echo
        echo "{\$TEST1} = ${!TEST1}"  #  Вывод на экран содержимого переменной.
                                      #  Это то, что дает
                                      #+ косвенная ссылка.
        echo
        echo "-------------------------------------------"; echo
        echo


        # Вывод переменной
        echo "Переменная VARIABLE: $VARIABLE"

        # Вывод элементов строки
        IFS="$OLD_IFS"
        TEST2="STRING[*]"
        local ${!TEST2}      # Косвенная ссылка (то же, что и выше).
        echo "Элемент VAR2: $VAR2 из строки STRING"

        # Вывод элемента массива
        TEST2="ARRAY21[*]"
        local ${!TEST2}      # Косвенная ссылка.
        echo "Элемент VAR1_1: $VAR1_1 из массива ARRAY21"
}

print
echo

exit 0
</pre>
          </div>

          <p>--</p>

          <p>С помощью массивов, на языке командной оболочки, вполне
          возможно реализовать алгоритм <span class="emphasis"><em class="EMPHASIS">Решета Эратосфена</em></span>. Конечно же
          -- это очень ресурсоемкая задача. В виде сценария она будет
          работать мучительно долго, так что лучше всего реализовать ее
          на каком либо другом, компилирующем, языке программирования,
          таком как C.</p>

          <div class="EXAMPLE">
            <a name="EX68"></a>

            <p><strong>Пример 25-8. Пример реализации алгоритма <span class="emphasis"><em class="EMPHASIS">Решето
            Эратосфена</em></span></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# sieve.sh

# Решето Эратосфена
# Очень старый алгоритм поиска простых чисел.

# Этот сценарий выполняется во много раз медленнее
# чем аналогичная программа на C.

LOWER_LIMIT=1       # Начиная с 1.
UPPER_LIMIT=1000    # До 1000.
# (Вы можете установить верхний предел и выше...  если вам есть чем себя занять.)

PRIME=1
NON_PRIME=0

declare -a Primes
# Primes[] -- массив.


initialize ()
{
# Инициализация массива.

i=$LOWER_LIMIT
until [ "$i" -gt "$UPPER_LIMIT" ]
do
  Primes[i]=$PRIME
  let "i += 1"
done
# Все числа в заданном диапазоне считать простыми,
# пока не доказано обратное.
}

print_primes ()
{
# Вывод индексов элементов массива Primes[], которые признаны простыми.

i=$LOWER_LIMIT

until [ "$i" -gt "$UPPER_LIMIT" ]
do

  if [ "${Primes[i]}" -eq "$PRIME" ]
  then
    printf "%8d" $i
    # 8 пробелов перед числом придают удобочитаемый табличный вывод на экран.
  fi

  let "i += 1"

done

}

sift () # Отсеивание составных чисел.
{

let i=$LOWER_LIMIT+1
# Нам известно, что 1 -- это простое число, поэтому начнем с 2.

until [ "$i" -gt "$UPPER_LIMIT" ]
do

if [ "${Primes[i]}" -eq "$PRIME" ]
# Не следует проверять вторично числа, которые уже признаны составными.
then

  t=$i

  while [ "$t" -le "$UPPER_LIMIT" ]
  do
    let "t += $i "
    Primes[t]=$NON_PRIME
    # Все числа, которые делятся на $t без остатка, пометить как составные.
  done

fi

  let "i += 1"
done


}


# Вызов функций.
initialize
sift
print_primes
# Это называется структурным программированием.

echo

exit 0



# ----------------------------------------------- #
# Код, приведенный ниже, не исполняется из-за команды exit, стоящей выше.

# Улучшенная версия, предложенная Stephane Chazelas,
# работает несколько быстрее.

# Должен вызываться с аргументом командной строки, определяющем верхний предел.

UPPER_LIMIT=$1                  # Из командной строки.
let SPLIT=UPPER_LIMIT/2         # Рассматривать делители только до середины диапазона.

Primes=( '' $(seq $UPPER_LIMIT) )

i=1
until (( ( i += 1 ) &gt; SPLIT ))  # Числа из верхней половины диапазона могут не рассматриваться.
do
  if [[ -n $Primes[i] ]]
  then
    t=$i
    until (( ( t += i ) &gt; UPPER_LIMIT ))
    do
      Primes[t]=
    done
  fi
done
echo ${Primes[*]}

exit 0
</pre>
          </div>

          <p>Сравните этот сценарий с генератором простых чисел, не
          использующим массивов, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PRIMES">Пример A-18</a>.</p>

          <p>--</p>

          <p>Массивы позволяют эмулировать некоторые структуры данных,
          поддержка которых в Bash не предусмотрена.</p>

          <div class="EXAMPLE">
            <a name="STACKEX"></a>

            <p><strong>Пример 25-9. Эмуляция структуры "СТЕК"
            ("первый вошел -- последний вышел")</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# stack.sh: Эмуляция структуры "СТЕК" ("первый вошел -- последний вышел")

#  Подобно стеку процессора, этот "стек" сохраняет и возвращает данные по принципу
#+ "первый вошел -- последний вышел".

BP=100            # Базовый указатель на массив-стек.
                  # Дно стека -- 100-й элемент.

SP=$BP            # Указатель вершины стека.
                  # Изначально -- стек пуст.

Data=             #  Содержимое вершины стека.
                  #  Следует использовать дополнительную переменную,
                  #+ из-за ограничений на диапазон возвращаемых функциями значений.

declare -a stack


push()            # Поместить элемент на вершину стека.
{
if [ -z "$1" ]    # А вообще, есть что помещать на стек?
then
  return
fi

let "SP -= 1"     # Переместить указатель стека.
stack[$SP]=$1

return
}

pop()                    # Снять элемент с вершины стека.
{
Data=                    # Очистить переменную.

if [ "$SP" -eq "$BP" ]   # Стек пуст?
then
  return
fi                       #  Это предохраняет от выхода SP за границу стека -- 100,

Data=${stack[$SP]}
let "SP += 1"            # Переместить указатель стека.
return
}

status_report()          # Вывод вспомогательной информации.
{
echo "-------------------------------------"
echo "ОТЧЕТ"
echo "Указатель стека SP = $SP"
echo "Со стека был снят элемент \""$Data"\""
echo "-------------------------------------"
echo
}


# =======================================================
# А теперь позабавимся.

echo

# Попробуем вытолкнуть что-нибудь из пустого стека.
pop
status_report

echo

push garbage
pop
status_report     # Втолкнуть garbage, вытолкнуть garbage.

value1=23; push $value1
value2=skidoo; push $value2
value3=FINAL; push $value3

pop              # FINAL
status_report
pop              # skidoo
status_report
pop              # 23
status_report    # Первый вошел -- последний вышел!

#  Обратите внимание как изменяется указатель стека на каждом вызове функций push и pop.

echo
# =======================================================


# Упражнения:
# -----------

# 1)  Измените функцию "push()" таким образом,
#   + чтобы она позволяла помещать на стек несколько значений за один вызов.

# 2)  Измените функцию "pop()" таким образом,
#   + чтобы она позволяла снимать со стека несколько значений за один вызов.

# 3)  Попробуйте написать простейший калькулятор, выполняющий 4 арифметических действия?
#   + используя этот пример.

exit 0
</pre>
          </div>

          <p>--</p>

          <p>Иногда, манипуляции с <span class="QUOTE">"индексами"</span> массивов могут
          потребовать введения переменных для хранения промежуточных
          результатов. В таких случаях вам предоставляется лишний повод
          подумать о реализации проекта на более мощном языке
          программирования, например Perl или C.</p>

          <div class="EXAMPLE">
            <a name="QFUNCTION"></a>

            <p><strong>Пример 25-10. <span class="emphasis"><em class="EMPHASIS">Исследование математических
            последовательностей</em></span></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# Пресловутая "Q-последовательность" Дугласа Хольфштадтера *Douglas Hofstadter):

# Q(1) = Q(2) = 1
# Q(n) = Q(n - Q(n-1)) + Q(n - Q(n-2)), для n&gt;2

# Это "хаотическая" последовательность целых чисел с непредсказуемым поведением.
# Первые 20 членов последовательности:
# 1 1 2 3 3 4 5 5 6 6 6 8 8 8 10 9 10 11 11 12

# См. книгу Дугласа Хольфштадтера, "Goedel, Escher, Bach: An Eternal Golden Braid",
# p. 137, ff.


LIMIT=100     # Найти первые 100 членов последовательности
LINEWIDTH=20  # Число членов последовательности, выводимых на экран в одной строке

Q[1]=1        # Первые два члена последовательности равны 1.
Q[2]=1

echo
echo "Q-последовательность [первые $LIMIT членов]:"
echo -n "${Q[1]} "             # Вывести первые два члена последовательности.
echo -n "${Q[2]} "

for ((n=3; n &lt;= $LIMIT; n++))  # C-подобное оформление цикла.
do   # Q[n] = Q[n - Q[n-1]] + Q[n - Q[n-2]]  для n&gt;2
# Это выражение необходимо разбить на отдельные действия,
# поскольку Bash не очень хорошо поддерживает сложные арифметические действия над элементами массивов.

  let "n1 = $n - 1"        # n-1
  let "n2 = $n - 2"        # n-2

  t0=`expr $n - ${Q[n1]}`  # n - Q[n-1]
  t1=`expr $n - ${Q[n2]}`  # n - Q[n-2]

  T0=${Q[t0]}              # Q[n - Q[n-1]]
  T1=${Q[t1]}              # Q[n - Q[n-2]]

Q[n]=`expr $T0 + $T1`      # Q[n - Q[n-1]] + Q[n - Q[n-2]]
echo -n "${Q[n]} "

if [ `expr $n % $LINEWIDTH` -eq 0 ]    # Если выведено очередные 20 членов в строке.
then   # то
  echo # перейти на новую строку.
fi

done

echo

exit 0

# Этот сценарий реализует итеративный алгоритм поиска членов Q-последовательности.
# Рекурсивную реализацию, как более интуитивно понятную, оставляю вам, в качестве упражнения.
# Внимание: рекурсивный поиск членов последовательности будет занимать *очень* продолжительное время.
</pre>
          </div>

          <p>--</p>

          <p>Bash поддерживает только одномерные массивы, но, путем
          небольших ухищрений, можно эмулировать многомерные
          массивы.</p>

          <div class="EXAMPLE">
            <a name="TWODIM"></a>

            <p><strong>Пример 25-11. Эмуляция массива с двумя
            измерениями</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Эмуляция двумерного массива.

# Второе измерение представлено как последовательность строк.

Rows=5
Columns=5

declare -a alpha     # char alpha [Rows] [Columns];
                     # Необязательное объявление массива.

load_alpha ()
{
local rc=0
local index


for i in A B C D E F G H I J K L M N O P Q R S T U V W X Y
do
  local row=`expr $rc / $Columns`
  local column=`expr $rc % $Rows`
  let "index = $row * $Rows + $column"
  alpha[$index]=$i   # alpha[$row][$column]
  let "rc += 1"
done

# Более простой вариант
#   declare -a alpha=( A B C D E F G H I J K L M N O P Q R S T U V W X Y )
# но при таком объявлении второе измерение массива завуалировано.
}

print_alpha ()
{
local row=0
local index

echo

while [ "$row" -lt "$Rows" ]   # Вывод содержимого массива построчно
do

  local column=0

  while [ "$column" -lt "$Columns" ]
  do
    let "index = $row * $Rows + $column"
    echo -n "${alpha[index]} "  # alpha[$row][$column]
    let "column += 1"
  done

  let "row += 1"
  echo

done

# Более простой эквивалент:
#   echo ${alpha[*]} | xargs -n $Columns

echo
}

filter ()     # Отфильтровывание отрицательных индексов.
{

echo -n "  "

if [[ "$1" -ge 0 &amp;&amp;  "$1" -lt "$Rows" &amp;&amp; "$2" -ge 0 &amp;&amp; "$2" -lt "$Columns" ]]
then
    let "index = $1 * $Rows + $2"
    echo -n " ${alpha[index]}"  # alpha[$row][$column]
fi

}

rotate ()  # Поворот массива на 45 градусов
{
local row
local column

for (( row = Rows; row &gt; -Rows; row-- ))  # В обратном порядке.
do

  for (( column = 0; column &lt; Columns; column++ ))
  do

    if [ "$row" -ge 0 ]
    then
      let "t1 = $column - $row"
      let "t2 = $column"
    else
      let "t1 = $column"
      let "t2 = $column + $row"
    fi

    filter $t1 $t2   # Отфильтровать отрицательный индекс.
  done

  echo; echo

done

# Поворот массива выполнен на основе примеров (стр. 143-146)
# из книги "Advanced C Programming on the IBM PC", автор Herbert Mayer
# (см. библиографию).

}


#-----------------------------------------------------#
load_alpha     # Инициализация массива.
print_alpha    # Вывод на экран.
rotate         # Повернуть на 45 градусов против часовой стрелки.
#-----------------------------------------------------#


# Упражнения:
# -----------
# 1)  Сделайте инициализацию и вывод массива на экран
#   + более простым и элегантным способом.
#
# 2)  Объясните принцип работы функции rotate().

exit 0
</pre>
          </div>

          <p>По существу, двумерный массив эквивалентен одномерному, с
          тем лишь различием, что для индексации отдельных элементов
          используются два индекса -- <span class="QUOTE">"строка"</span> и <span class="QUOTE">"столбец"</span>.</p>

          <p>Более сложный пример эмуляции двумерного массива вы
          найдете в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LIFESLOW">Пример A-11</a>.</p>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="FILES"></a>Глава 26. Файлы</h1>

          <div class="VARIABLELIST">
            <p><strong><a name="FILESREF1"></a>сценарии начальной
            загрузки</strong></p>

            <dl>
              <dd>
                <p>Эти файлы содержат объявления псевдонимов и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ENVREF">переменных окружения</a>, которые
                становятся доступны Bash после загрузки и инициализации
                системы.</p>
              </dd>

              <dt><code class="FILENAME">/etc/profile</code></dt>

              <dd>
                <p>Настройки системы по-умолчанию, главным образом
                настраивается окружение командной оболочки (все
                Bourne-подобные оболочки, не только Bash <a name="AEN12906" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN12906"><span class="footnote">[55]</span></a>)</p>
              </dd>

              <dt><code class="FILENAME">/etc/bashrc</code></dt>

              <dd>
                <p>функции и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ALIASREF">псевдонимы</a> Bash</p>
              </dd>

              <dt><code class="FILENAME"><code class="VARNAME">$HOME</code>/.bash_profile</code></dt>

              <dd>
                <p>пользовательские настройки окружения Bash, находится
                в домашнем каталоге у каждого пользователя (локальная
                копия файла <code class="FILENAME">/etc/profile</code>)</p>
              </dd>

              <dt><code class="FILENAME"><code class="VARNAME">$HOME</code>/.bashrc</code></dt>

              <dd>
                <p>пользовательский файл инициализации Bash, находится
                в домашнем каталоге у каждого пользователя (локальная
                копия файла <code class="FILENAME">/etc/bashrc</code>). См. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SAMPLE-BASHRC">Приложение G</a>пример файла <code class="FILENAME">.bashrc</code>.</p>
              </dd>
            </dl>
          </div>

          <div class="VARIABLELIST">
            <p><strong><a name="LOGOUTFILEREF1"></a>Сценарий выхода из системы
            (logout)</strong></p>

            <dl>
              <dt><code class="FILENAME"><code class="VARNAME">$HOME</code>/.bash_logout</code></dt>

              <dd>
                <p>Этот сценарий отрабатывает, когда пользователь
                выходит из системы.</p>
              </dd>
            </dl>
          </div>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="DEVPROC"></a>Глава 27. /dev и /proc</h1>

          <p><a name="DEVPROCREF"></a></p>

          <p>Как правило, Linux или UNIX система имеет два каталога
          специального назначения: <code class="FILENAME">/dev</code> и <code class="FILENAME">/proc</code>.</p>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="DEVREF1"></a>27.1. <code class="FILENAME">/dev</code></h2>

            <p>Каталог <code class="FILENAME">/dev</code> содержит файлы физических <span class="emphasis"><em class="EMPHASIS">устройств</em></span>, которые могут
            входить в состав аппаратного обеспечения компьютера. <a name="AEN12955" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN12955"><span class="footnote">[56]</span></a> Каждому из разделов не
            жестком диске соответствует свой файл-устройство в каталоге
            <code class="FILENAME">/dev</code>, информация о которых может
            быть получена простой командой <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DFREF">df</a>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>df</strong></code>
<code class="COMPUTEROUTPUT">Filesystem           1k-blocks      Used Available Use%
 Mounted on
 /dev/hda6               495876    222748    247527  48% /
 /dev/hda1                50755      3887     44248   9% /boot
 /dev/hda8               367013     13262    334803   4% /home
 /dev/hda5              1714416   1123624    503704  70% /usr</code>
             
</pre>
            <br>
            <br>

            <p><a name="LOOPBACKREF"></a>Кроме того, каталог <code class="FILENAME">/dev</code> содержит <span class="emphasis"><em class="EMPHASIS">loopback</em></span>-устройства
            ("петлевые" устройства), например <code class="FILENAME">/dev/loop0</code>. С помощью такого
            устройства можно представить обычный файл как блочное
            устройство ввода/вывода. <a name="AEN12973" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN12973"><span class="footnote">[57]</span></a> Это позволяет монтировать
            целые файловые системы, находящиеся в отдельных больших
            файлах. См. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CREATEFS">Пример 13-6</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ISOMOUNTREF">Пример 13-5</a>.</p>

            <p>Отдельные псевдоустройства в <code class="FILENAME">/dev</code> имеют особое назначение, к
            таким устройствам можно отнести <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ZEROSREF"><code class="FILENAME">/dev/null</code></a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ZEROSREF1"><code class="FILENAME">/dev/zero</code></a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#URANDOMREF"><code class="FILENAME">/dev/urandom</code></a>.</p>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="PROCREF1"></a>27.2. <code class="FILENAME">/proc</code></h2>

            <p>Фактически, каталог <code class="FILENAME">/proc</code> -- это виртуальная файловая
            система. Файлы, в каталоге <code class="FILENAME">/proc</code>, содержат информацию о
            процессах, о состоянии и конфигурации ядра и системы.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>cat /proc/devices</strong></code>
<code class="COMPUTEROUTPUT">Character devices:
   1 mem
   2 pty
   3 ttyp
   4 ttyS
   5 cua
   7 vcs
  10 misc
  14 sound
  29 fb
  36 netlink
 128 ptm
 136 pts
 162 raw
 254 pcmcia

 Block devices:
   1 ramdisk
   2 fd
   3 ide0
   9 md</code>



<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>cat /proc/interrupts</strong></code>
 <code class="COMPUTEROUTPUT">          CPU0
   0:      84505          XT-PIC  timer
   1:       3375          XT-PIC  keyboard
   2:          0          XT-PIC  cascade
   5:          1          XT-PIC  soundblaster
   8:          1          XT-PIC  rtc
  12:       4231          XT-PIC  PS/2 Mouse
  14:     109373          XT-PIC  ide0
 NMI:          0
 ERR:          0</code>



<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>cat /proc/partitions</strong></code>
<code class="COMPUTEROUTPUT">major minor  #blocks  name     rio rmerge rsect ruse wio wmerge wsect wuse running use aveq

    3     0    3007872 hda 4472 22260 114520 94240 3551 18703 50384 549710 0 111550 644030
    3     1      52416 hda1 27 395 844 960 4 2 14 180 0 800 1140
    3     2          1 hda2 0 0 0 0 0 0 0 0 0 0 0
    3     4     165280 hda4 10 0 20 210 0 0 0 0 0 210 210
    ...</code>



<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>cat /proc/loadavg</strong></code>
<code class="COMPUTEROUTPUT">0.13 0.42 0.27 2/44 1119</code>
        
</pre>
            <br>
            <br>

            <p>Сценарии командной оболочки могут извлекать необходимую
            информацию из соответствующих файлов в каталоге <code class="FILENAME">/proc</code>. <a name="AEN13009" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN13009"><span class="footnote">[58]</span></a></p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>cat /proc/filesystems | grep iso9660</strong></code>
 <code class="COMPUTEROUTPUT">       iso9660</code>

             
</pre>
            <br>
            <br>
<pre class="PROGRAMLISTING">kernel_version=$( awk '{ print $3 }' /proc/version )
</pre>
            <br>
            <br>
<pre class="PROGRAMLISTING">CPU=$( awk '/model name/ {print $4}' &lt; /proc/cpuinfo )

if [ $CPU = Pentium ]
then
  выполнить_ряд_специфичных_команд
  ...
else
  выполнить_ряд_других_специфичных_команд
  ...
fi
</pre>
            <br>
            <br>

            <p>В каталоге <code class="FILENAME">/proc</code> вы наверняка заметите большое
            количество подкаталогов, с не совсем обычными именами,
            состоящими только из цифр. Каждый из них соответствует
            исполняющемуся процессу, а имя каталога -- это <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PPIDREF">ID (идентификатор) процесса</a>. Внутри
            каждого такого подкаталога находится ряд файлов, в которых
            содержится полезная информация о соответствующих процессах.
            Файлы <code class="FILENAME">stat</code> и <code class="FILENAME">status</code> хранят статистику работы
            процесса, <code class="FILENAME">cmdline</code> -- команда, которой был
            запущен процесс, <code class="FILENAME">exe</code> -- символическая ссылка на
            исполняемый файл программы. Здесь же вы найдете ряд других
            файлов, но, с точки зрения написания сценариев, они не так
            интересны, как эти четыре.</p>

            <div class="EXAMPLE">
              <a name="PIDID"></a>

              <p><strong>Пример 27-1. Поиск файла программы по
              идентификатору процесса</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# pid-identifier.sh: Возвращает полный путь к исполняемому файлу программы по идентификатору процесса (pid).

ARGNO=1  # Число, ожидаемых из командной строки, аргументов.
E_WRONGARGS=65
E_BADPID=66
E_NOSUCHPROCESS=67
E_NOPERMISSION=68
PROCFILE=exe

if [ $# -ne $ARGNO ]
then
  echo "Порядок использования: `basename $0` PID-процесса" &gt;&amp;2  # Сообщение об ошибке на &gt;stderr.
  exit $E_WRONGARGS
fi

ps ax

pidno=$( ps ax | grep $1 | awk '{ print $1 }' | grep $1 )
# Проверка наличия процесса с заданным pid в списке, выданном командой  "ps", поле #1.
# Затем следует убедиться, что этот процесс не был запущен этим сценарием ('ps').
# Это делает последний "grep $1".
if [ -z "$pidno" ]  # Если после фильтрации получается пустая строка,
then                # то это означает, что в системе нет процесса с заданым pid.
  echo "Нет такого процесса."
  exit $E_NOSUCHPROCESS
fi

# Альтернативный вариант:
#   if ! ps $1 &gt; /dev/null 2&gt;&amp;1
#   then                # в системе нет процесса с заданым pid.
#     echo "Нет такого процесса."
#     exit $E_NOSUCHPROCESS
#    fi


if [ ! -r "/proc/$1/$PROCFILE" ]  # Проверить право на чтение.
then
  echo "Процесс $1 найден, однако..."
  echo "у вас нет права на чтение файла /proc/$1/$PROCFILE."
  exit $E_NOPERMISSION  # Обычный пользователь не имеет прав
                        # на доступ к некоторым файлам в каталоге /proc.
fi

# Последние две проверки могут быть заменены на:
#    if ! kill -0 $1 &gt; /dev/null 2&gt;&amp;1 # '0' -- это не сигнал, но
                                      # команда все равно проверит наличие
                                      # процесса-получателя.
#    then echo "Процесс с данным PID не найден, либо вы не являетесь его владельцем" &gt;&amp;2
#    exit $E_BADPID
#    fi



exe_file=$( ls -l /proc/$1 | grep "exe" | awk '{ print $11 }' )
# Или      exe_file=$( ls -l /proc/$1/exe | awk '{print $11}' )
#
# /proc/pid-number/exe -- это символическая ссылка
# на исполняемый файл работающей программы.

if [ -e "$exe_file" ]  # Если файл /proc/pid-number/exe существует...
then                 # то существует и соответствующий процесс.
  echo "Исполняемый файл процесса #$1: $exe_file."
else
  echo "Нет такого процесса."
fi


# В большинстве случаев, этот, довольно сложный сценарий, может быть заменен командой
# ps ax | grep $1 | awk '{ print $5 }'
# В большинстве, но не всегда...
# поскольку пятое поле листинга,выдаваемого командой 'ps', это argv[0] процесса,
# а не путь к исполняемому файлу.
#
# Однако, оба следующих варианта должны работать безотказно.
#       find /proc/$1/exe -printf '%l\n'
#       lsof -aFn -p $1 -d txt | sed -ne 's/^n//p'

# Автор последнего комментария: Stephane Chazelas.

exit 0
</pre>
            </div>

            <div class="EXAMPLE">
              <a name="CONSTAT"></a>

              <p><strong>Пример 27-2. Проверка состояния
              соединения</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

PROCNAME=pppd        # демон ppp
PROCFILENAME=status  # Что смотреть.
NOTCONNECTED=65
INTERVAL=2           # Период проверки -- раз в 2 секунды.

pidno=$( ps ax | grep -v "ps ax" | grep -v grep | grep $PROCNAME | awk '{ print $1 }' )
# Найти идентификатор процесса 'pppd', 'ppp daemon'.
# По пути убрать из листинга записи о процессах, порожденных сценарием.
#
#  Однако, как отмечает Oleg Philon,
#+ Эта последовательность команд может быть заменена командой "pidof".
#  pidno=$( pidof $PROCNAME )
#
#  Мораль:
#+ Когда последовательность команд становится слишком сложной,
#+ это повод к тому, чтобы поискать более короткий вариант.


if [ -z "$pidno" ]   # Если получилась пустая строка, значит процесс не запущен.
then
  echo "Соединение не установлено."
  exit $NOTCONNECTED
else
  echo "Соединение установлено."; echo
fi

while [ true ]       # Бесконечный цикл.
do

  if [ ! -e "/proc/$pidno/$PROCFILENAME" ]
  # Пока работает процесс, файл "status" существует.
  then
    echo "Соединение разорвано."
    exit $NOTCONNECTED
  fi

netstat -s | grep "packets received"  # Получить некоторые сведения о соединении.
netstat -s | grep "packets delivered"


  sleep $INTERVAL
  echo; echo

done

exit 0

# Как обычно, этот сценарий может быть остановлен комбинацией клавиш Control-C.

#    Упражнение:
#    ----------
#    Добавьте возможность завершения работы сценария, по нажатии на клавишу "q".
#    Это сделает скрипт более жружественным к пользователю.
</pre>
            </div>

            <div class="WARNING">
              <table class="WARNING" width="100%" border="0">
                <tbody><tr>
                  <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/warning.gif" hspace="5" alt="Warning"></td>

                  <td align="left" valign="top">
                    <p>Будьте предельно осторожны при работе с файловой
                    системой <code class="FILENAME">/proc</code>, так как попытка
                    записи в некоторые файлы может повредить файловую
                    систему или привести к краху системы.</p>
                  </td>
                </tr>
              </tbody></table>
            </div>
          </div>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="ZEROS"></a>Глава 28. /dev/zero и /dev/null</h1>

          <p><a name="ZEROSREF"></a></p>

          <div class="VARIABLELIST">
            <p><strong><a name="ZERONULL1"></a></strong></p>

            <dl>
              <dt><code class="FILENAME">/dev/null</code></dt>

              <dd>
                <p>Псевдоустройство <code class="FILENAME">/dev/null</code> -- это, своего рода,
                <span class="QUOTE">"черная дыра"</span> в
                системе. Это, пожалуй, самый близкий смысловой
                эквивалент. Все, что записывается в этот файл,
                "исчезает" навсегда. Попытки записи или
                чтения из этого файла не дают, ровным счетом, никакого
                результата. Тем не менее, псевдоустройство <code class="FILENAME">/dev/null</code> вполне может
                пригодиться.</p>

                <p>Подавление вывода на <code class="FILENAME">stdout</code>.</p>
<pre class="PROGRAMLISTING">cat $filename &gt;/dev/null
# Содержимое файла $filename не появится на stdout.
</pre>
                <br>
                <br>

                <p>Подавление вывода на <code class="FILENAME">stderr</code> (from <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX57">Пример 12-2</a>).</p>
<pre class="PROGRAMLISTING">rm $badname 2&gt;/dev/null
#           Сообщение об ошибке "уйдет в никуда".
</pre>
                <br>
                <br>

                <p>Подавление вывода, как на <code class="FILENAME">stdout</code>, так и на <code class="FILENAME">stderr</code>.</p>
<pre class="PROGRAMLISTING">cat $filename 2&gt;/dev/null &gt;/dev/null
# Если "$filename" не будет найден, то вы не увидите сообщения об ошибке.
# Если "$filename" существует, то вы не увидите его содержимое.
# Таким образом, вышеприведенная команда ничего не выводит на экран.
#
#  Такая методика бывает полезной, когда необходимо лишь проверить код завершения команды
#+ и нежелательно выводить результат работы команды на экран.
#
# cat $filename &amp;&gt;/dev/null
#     дает тот же результат, автор примечания Baris Cicek.
</pre>
                <br>
                <br>

                <p>Удаление содержимого файла, сохраняя, при этом, сам
                файл, со всеми его правами доступа (очистка файла) (из
                <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX1">Пример 2-1</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX2">Пример 2-2</a>):</p>
<pre class="PROGRAMLISTING">cat /dev/null &gt; /var/log/messages
#  : &gt; /var/log/messages   дает тот же эффект, но не порождает дочерний процесс.

cat /dev/null &gt; /var/log/wtmp
</pre>
                <br>
                <br>

                <p>Автоматическая очистка содержимого системного
                журнала (logfile) (особенно хороша для борьбы с
                надоедливыми рекламными идентификационными файлами
                (<span class="QUOTE">"cookies"</span>)):</p>

                <div class="EXAMPLE">
                  <a name="COOKIES"></a>

                  <p><strong>Пример 28-1. Удаление
                  cookie-файлов</strong></p>
<pre class="PROGRAMLISTING">if [ -f ~/.netscape/cookies ]  # Удалить, если имеются.
then
  rm -f ~/.netscape/cookies
fi

ln -s /dev/null ~/.netscape/cookies
# Теперь, все cookie-файлы, вместо того, чтобы сохраняться на диске, будут "вылетать в трубу".
</pre>
                </div>
              </dd>

              <dt><a name="ZEROSREF1"></a><code class="FILENAME">/dev/zero</code></dt>

              <dd>
                <p>Подобно псевдоустройству <code class="FILENAME">/dev/null</code>, <code class="FILENAME">/dev/zero</code> так же является
                псевдоустройством, с той лишь разницей, что содержит
                нули. Информация, выводимая в этот файл, так же
                бесследно исчезает. Чтение нулей из этого файла может
                вызвать некоторые затруднения, однако это можно
                сделать, к примеру, с помощью команды <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ODREF">od</a> или шестнадцатиричного редактора.
                В основном, <code class="FILENAME">/dev/zero</code> используется для
                создания заготовки файла с заданой длиной.</p>

                <div class="EXAMPLE">
                  <a name="EX73"></a>

                  <p><strong>Пример 28-2. Создание файла подкачки
                  (swapfile), с помощью <code class="FILENAME">/dev/zero</code></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# Создание файла подкачки.
# Этот сценарий должен запускаться с правами root.

ROOT_UID=0         # Для root -- $UID 0.
E_WRONG_USER=65    # Не root?

FILE=/swap
BLOCKSIZE=1024
MINBLOCKS=40
SUCCESS=0

if [ "$UID" -ne "$ROOT_UID" ]
then
  echo; echo "Этот сценарий должен запускаться с правами root."; echo
  exit $E_WRONG_USER
fi


blocks=${1:-$MINBLOCKS}          #  По-умолчанию -- 40 блоков,
                                 #+ если размер не задан из командной строки.
# Ниже приводится эквивалентный набор команд.
# --------------------------------------------------
# if [ -n "$1" ]
# then
#   blocks=$1
# else
#   blocks=$MINBLOCKS
# fi
# --------------------------------------------------


if [ "$blocks" -lt $MINBLOCKS ]
then
  blocks=$MINBLOCKS              # Должно быть как минимум 40 блоков.
fi


echo "Создание файла подкачки размером $blocks блоков (KB)."
dd if=/dev/zero of=$FILE bs=$BLOCKSIZE count=$blocks  # "Забить" нулями.

mkswap $FILE $blocks             # Назначить как файл подкачки.
swapon $FILE                     # Активировать.

echo "Файл подкачки создан и активирован."

exit $SUCCESS
</pre>
                </div>

                <p>Еще одна область применения <code class="FILENAME">/dev/zero</code> -- <span class="QUOTE">"очистка"</span> специального
                файла заданного размера, например файлов, монтируемых
                как <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LOOPBACKREF">loopback-устройства</a> (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CREATEFS">Пример 13-6</a>) или для безопасного
                удаления файла (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BLOTOUT">Пример 12-42</a>).</p>

                <div class="EXAMPLE">
                  <a name="RAMDISK"></a>

                  <p><strong>Пример 28-3. Создание электронного
                  диска</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# ramdisk.sh

#  "электронный диск" -- это область в ОЗУ компьютера
#+ с которой система взаимодействует как с файловой системой.
#  Основное преимущество -- очень высокая скорость чтения/записи.
#  Недостатки -- энергозависимость, уменьшение объема ОЗУ, доступного системе,
#                относительно небольшой размер.
#
#  Чем хорош электронный диск?
#  При хранении наборов данных, таких как таблиц баз данных или словарей, на электронном диске
#+ вы получаете высокую скорость работы с этими наборами, поскольку время доступа к ОЗУ
#  неизмеримо меньше времени доступа к жесткому диску.


E_NON_ROOT_USER=70             # Сценарий должен запускаться с правами root.
ROOTUSER_NAME=root

MOUNTPT=/mnt/ramdisk
SIZE=2000                      # 2K блоков (измените, если это необходимо)
BLOCKSIZE=1024                 # размер блока -- 1K (1024 байт)
DEVICE=/dev/ram0               # Первое устройство ram

username=`id -nu`
if [ "$username" != "$ROOTUSER_NAME" ]
then
  echo "Сценарий должен запускаться с правами root."
  exit $E_NON_ROOT_USER
fi

if [ ! -d "$MOUNTPT" ]         #  Проверка наличия точки монтирования,
then                           #+ благодаря этой проверке, при повторных запусках сценария
  mkdir $MOUNTPT               #+ ошибки возникать не будет.
fi

dd if=/dev/zero of=$DEVICE count=$SIZE bs=$BLOCKSIZE  # Очистить электронный диск.
mke2fs $DEVICE                 # Создать файловую систему ext2.
mount $DEVICE $MOUNTPT         # Смонтировать.
chmod 777 $MOUNTPT             # Сделать электронный диск доступным для обычных пользователей.
                               # Но при этом, только root сможет его отмонтировать.

echo "Электронный диск \"$MOUNTPT\" готов к работе."
# Теперь электронный диск доступен для любого пользователя в системе.

#  Внимание! Электронный диск -- это энергозависимое устройство! Все данные, хранящиеся на нем,
#+ будут утеряны при остановке или перезагрузке системы.
#  Если эти данные представляют для вас интерес, то сохраняйте их копии в обычном каталоге.

# После перезагрузки, чтобы вновь создать электронный диск, запустите этот сценарий.
# Простое монтирование /mnt/ramdisk, без выполнения подготовительных действий, не будет работать.

exit 0
</pre>
                </div>
              </dd>
            </dl>
          </div>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="DEBUGGING"></a>Глава 29. Отладка сценариев</h1>

          <p>Командная оболочка Bash не имеет своего отладчика, и не
          имеет даже каких либо отладочных команд или конструкций. <a name="AEN13102" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN13102"><span class="footnote">[59]</span></a> Синтаксические ошибки или
          опечатки часто вызывают сообщения об ошибках, которые которые
          практически никак не помогают при отладке.</p>

          <div class="EXAMPLE">
            <a name="EX74"></a>

            <p><strong>Пример 29-1. Сценарий, содержащий
            ошибку</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# ex74.sh

# Этот сценарий содержит ошибку.

a=37

if [$a -gt 27 ]
then
  echo $a
fi  

exit 0
</pre>
          </div>

          <p>В результате исполнения этого сценария вы получите такое
          сообщение:</p>
<pre class="SCREEN"><code class="COMPUTEROUTPUT">./ex74.sh: [37: command not found</code>
</pre>
          Что в этом сценарии может быть неправильно (подсказка: после
          ключевого слова <strong class="COMMAND">if</strong>)?<br>
          <br>

          <div class="EXAMPLE">
            <a name="MISSINGKEYWORD"></a>

            <p><strong>Пример 29-2. Пропущено <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#KEYWORDREF">ключевое слово</a></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# missing-keyword.sh:
# Какое сообщение об ошибке будет выведено, при попытке запустить этот сценарий?

for a in 1 2 3
do
  echo "$a"
# done     # Необходимое ключевое слово 'done' закомментировано.

exit 0
</pre>
          </div>

          <p>На экране появится сообщение:</p>
<pre class="SCREEN"><code class="COMPUTEROUTPUT">missing-keyword.sh: line 11: syntax error: unexpected end of file</code>
       
</pre>
          Обратите внимание, сообщение об ошибке будет содержать номер
          не той строки, в которой возникла ошибка, а той, в которой
          Bash точно установил наличие ошибочной ситуации. <br>
          <br>

          <p>Сообщения об ошибках могут вообще не содержать номера
          строки, при исполнении которой эта ошибка появилась.</p>

          <p>А что делать, если сценарий работает, но не так как
          ожидалось? Вот пример весьма распространенной логической
          ошибки.</p>

          <div class="EXAMPLE">
            <a name="EX75"></a>

            <p><strong>Пример 29-3. test24</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

#  Ожидается, что этот сценарий будет удалять в текущем каталоге
#+ все файлы, имена которых содержат пробелы.
#  Но он не работает.  Почему?


badname=`ls | grep ' '`

# echo "$badname"

rm "$badname"

exit 0
</pre>
          </div>

          <p>Попробуйте найти ошибку, раскомментарив строку <code class="USERINPUT"><strong>echo
          "$badname"</strong></code>. Инструкция echo очень
          полезна при отладке сценариев, она позволяет узнать --
          действительно ли вы получаете то, что ожидали получить.</p>

          <p>В данном конкретном случае, команда <code class="USERINPUT"><strong>rm
          "$badname"</strong></code> не дает желаемого
          результата потому, что переменная <code class="VARNAME">$badname</code> взята в кавычки. В результате,
          <strong class="COMMAND">rm</strong> получает единственный аргумент
          (т.е. команда будет считать, что получила имя одного файла).
          Частично эта проблема может быть решена за счет удаления
          кавычек вокруг <code class="VARNAME">$badname</code> и установки переменной <code class="VARNAME">$IFS</code> так, чтобы она содержала только
          символ перевода строки, <code class="USERINPUT"><strong>IFS=$'\n'</strong></code>.
          Однако, существует более простой способ выполнить эту
          задачу.</p>
<pre class="PROGRAMLISTING"># Правильный способ удаления файлов, в чьих именах содержатся пробелы.
rm *\ *
rm *" "*
rm *' '*
# Спасибо S.C.
</pre>
          <br>
          <br>

          <p>В общих чертах, ошибочными можно считать такие сценарии,
          которые</p>

          <ol type="1">
            <li>
              <p>"сыплют" сообщениями о <span class="QUOTE">"<span class="ERRORNAME">синтаксических
              ошибках</span>"</span> или</p>
            </li>

            <li>
              <p>запускаются, но работают не так как ожидалось (<span class="ERRORNAME">логические ошибки</span>).</p>
            </li>

            <li>
              <p>запускаются, делают то, что требуется, но имеют
              побочные эффекты (<span class="ERRORNAME">логическая бомба</span>).</p>
            </li>
          </ol>
          <br>
          <br>

          <p>Инструменты, которые могут помочь при отладке неработающих
          сценариев</p>

          <ol type="1">
            <li>
              <p>команда echo, в критических точках сценария, поможет
              отследить состояние переменных и отобразить ход
              исполнения.</p>
            </li>

            <li>
              <p>команда-фильтр <strong class="COMMAND">tee</strong>, которая поможет проверить
              процессы и потоки данных в критических местах.</p>
            </li>

            <li>
              <p>ключи <code class="OPTION">-n -v -x</code></p>

              <p><code class="USERINPUT"><strong>sh -n scriptname</strong></code>
              -- проверит наличие синтаксических ошибок, не запуская
              сам сценарий. Того же эффекта можно добиться, вставив в
              сценарий команду <code class="USERINPUT"><strong>set -n</strong></code> или <code class="USERINPUT"><strong>set -o noexec</strong></code>.
              Обратите внимание, некоторые из синтаксических ошибок не
              могут быть выявлены таким способом.</p>

              <p><code class="USERINPUT"><strong>sh -v scriptname</strong></code>
              -- выводит каждую команду прежде, чем она будет
              выполнена. Того же эффекта можно добиться, вставив в
              сценарий команду <code class="USERINPUT"><strong>set -v</strong></code> или <code class="USERINPUT"><strong>set -o
              verbose</strong></code>.</p>

              <p>Ключи <code class="OPTION">-n</code> и <code class="OPTION">-v</code> могут употребляться совместно:
              <code class="USERINPUT"><strong>sh -nv
              scriptname</strong></code>.</p>

              <p><code class="USERINPUT"><strong>sh -x scriptname</strong></code>
              -- выводит, в краткой форме, результат исполнения каждой
              команды. Того же эффекта можно добиться, вставив в
              сценарий команду <code class="USERINPUT"><strong>set -x</strong></code> или <code class="USERINPUT"><strong>set -o
              xtrace</strong></code>.</p>

              <p>Вставив в сценарий <code class="USERINPUT"><strong>set -u</strong></code> или <code class="USERINPUT"><strong>set -o nounset</strong></code>,
              вы будете получать сообщение об ошибке <span class="ERRORNAME">unbound variable</span> всякий раз,
              когда будет производиться попытка обращения к
              необъявленной переменной.</p>
            </li>

            <li>
              <p>Функция <span class="QUOTE">"assert"</span>, предназначенная
              для проверки переменных или условий, в критических точках
              сценария. (Эта идея заимствована из языка
              программирования C.)</p>

              <div class="EXAMPLE">
                <a name="ASSERT"></a>

                <p><strong>Пример 29-4. Проверка условия с помощью
                функции <span class="QUOTE">"assert"</span></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# assert.sh

assert ()                 #  Если условие ложно,
{                         #+ выход из сценария с сообщением об ошибке.
  E_PARAM_ERR=98
  E_ASSERT_FAILED=99


  if [ -z "$2" ]          # Недостаточное количество входных параметров.
  then
    return $E_PARAM_ERR
  fi

  lineno=$2

  if [ ! $1 ]
  then
    echo "Утверждение ложно:  \"$1\""
    echo "Файл: \"$0\", строка: $lineno"
    exit $E_ASSERT_FAILED
  # else
  #   return
  #   и продолжить исполнение сценария.
  fi
}


a=5
b=4
condition="$a -lt $b"     # Сообщение об ощибке и завершение сценария.
                          #  Попробуйте поменять условие "condition"
                          #+ на что нибудь другое и
                          #+ посмотреть -- что получится.

assert "$condition" $LINENO
# Сценарий продолжит работу только в том случае, если утверждение истинно.


# Прочие команды.
# ...
echo "Эта строка появится на экране только если утверждение истинно."
# ...
# Прочие команды.
# ...

exit 0
</pre>
              </div>
            </li>

            <li>
              <p>Ловушка на выхто в этом сценарии может быть
              неправильно (подсказка: после ключевого словоде.</p>

              <p>Команда <strong class="COMMAND">exit</strong>, в сценарии, порождает
              сигнал <span class="RETURNVALUE">0</span>, по которому процесс
              завершает работу, т.е. -- сам сценарий. <a name="AEN13188" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN13188"><span class="footnote">[60]</span></a> Часто бывает полезным
              по выходу из сценария выдать <span class="QUOTE">"распечатку"</span>
              переменных.</p>
            </li>
          </ol>
          <br>
          <br>

          <div class="VARIABLELIST">
            <p><strong><a name="TRAPREF1"></a>Установка ловушек на
            сигналы</strong></p>

            <dl>
              <dt><strong class="COMMAND">trap</strong></dt>

              <dd>
                <p>Определяет действие при получении сигнала; так же
                полезна при отладке.</p>

                <div class="NOTE">
                  <table class="NOTE" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                      <td align="left" valign="top">
                        <p><a name="SIGNALD"></a>Сигнал (<span class="emphasis"><em class="EMPHASIS">signal</em></span>) -- это
                        просто сообщение, передается процессу либо
                        ядром, либо другим процессом, чтобы побудить
                        процесс выполнить какие либо действия (обычно
                        -- завершить работу). Например, нажатие на
                        <strong class="KEYCAP">Control</strong>-<strong class="KEYCAP">C</strong>, вызывает передачу
                        сигнала SIGINT, исполняющейся программе.</p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>
<pre class="PROGRAMLISTING">trap '' 2
# Игнорировать прерывание 2 (Control-C), действие по сигналу не указано.

trap 'echo "Control-C disabled."' 2
# Сообщение при нажатии на Control-C.
</pre>
                <br>
                <br>
              </dd>
            </dl>
          </div>

          <div class="EXAMPLE">
            <a name="EX76"></a>

            <p><strong>Пример 29-5. Ловушка на выходе</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

trap 'echo Список переменных --- a = $a  b = $b' EXIT
# EXIT -- это название сигнала, генерируемого при выходе из сценария.

a=39

b=36

exit 0
# Примечательно, что если закомментировать команду 'exit',
# то это никак не скажется на работе сценария,
# поскольку "выход" из сценария происходит в любом случае.
</pre>
          </div>

          <div class="EXAMPLE">
            <a name="ONLINE"></a>

            <p><strong>Пример 29-6. Удаление временного файла при
            нажатии на Control-C</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# logon.sh: Сценарий, написаный "на скорую руку", контролирует вход в режим on-line.


TRUE=1
LOGFILE=/var/log/messages
# Обратите внимание: $LOGFILE должен быть доступен на чтение (chmod 644 /var/log/messages).
TEMPFILE=temp.$$
# "Уникальное" имя для временного файла, где расширение в имени -- это pid процесса-сценария.
KEYWORD=address
# При входе, в файл /var/log/messages,
# добавляется  строка "remote IP address xxx.xxx.xxx.xxx"
ONLINE=22
USER_INTERRUPT=13
CHECK_LINES=100
# Количество проверяемых строк.

trap 'rm -f $TEMPFILE; exit $USER_INTERRUPT' TERM INT
# Удалить временный файл, когда сценарий завершает работу по control-c.

echo

while [ $TRUE ]  #Бесконечный цикл.
do
  tail -$CHECK_LINES $LOGFILE&gt; $TEMPFILE
  # Последние 100 строк из системного журнала переписать во временный файл.
  # Совершенно необходимо, т.к. новейшие версии ядер генерируют много сообщений при входе.
  search=`grep $KEYWORD $TEMPFILE`
  # Проверить наличие фразы "address",
  # свидетельствующей об успешном входе.

  if [ ! -z "$search" ] # Кавычки необходимы, т.к. переменная может содержать пробелы.
  then
     echo "On-line"
     rm -f $TEMPFILE    # Удалить временный файл.
     exit $ONLINE
  else
     echo -n "."        # ключ -n подавляет вывод символа перевода строки,
                        # так вы получите непрерывную строку точек.
  fi

  sleep 1
done


# Обратите внимание: если изменить содержимое переменной KEYWORD
# на "Exit", то сценарий может использоваться для контроля
# неожиданного выхода (logoff).

exit 0

# Nick Drage предложил альтернативный метод:

while true
  do ifconfig ppp0 | grep UP 1&gt; /dev/null &amp;&amp; echo "соединение установлено" &amp;&amp; exit 0
  echo -n "."   # Печать последовательности точек (.....), пока соединение не будет установлено.
  sleep 2
done

# Проблема: Нажатия Control-C может оказаться недостаточным, чтобы завершить этот процесс.
#          (Точки продолжают выводиться на экран.)
# Упражнение: Исправьте этот недостаток.



# Stephane Chazelas предложил еще одну альтернативу:

CHECK_INTERVAL=1

while ! tail -1 "$LOGFILE" | grep -q "$KEYWORD"
do echo -n .
   sleep $CHECK_INTERVAL
done
echo "On-line"

# Упражнение: Найдите сильные и слабые стороны
#           каждого из этих подходов.
</pre>
          </div>

          <div class="NOTE">
            <table class="NOTE" width="100%" border="0">
              <tbody><tr>
                <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                <td align="left" valign="top">
                  <p>Аргумент <code class="OPTION">DEBUG</code>, команды <strong class="COMMAND">trap</strong>, заставляет сценарий
                  выполнять указанное действие после выполнения каждой
                  команды. Это можно использовать для трассировки
                  переменных.</p>

                  <div class="EXAMPLE">
                    <a name="VARTRACE"></a>

                    <p><strong>Пример 29-7. Трассировка
                    переменной</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

trap 'echo "VARIABLE-TRACE&gt; $LINENO: \$variable = \"$variable\""' DEBUG
# Выводить значение переменной после исполнения каждой команды.

variable=29

echo "Переменная \"\$variable\" инициализирована числом $variable."

let "variable *= 3"
echo "Значение переменной \"\$variable\" увеличено в 3 раза."

# Конструкция "trap 'commands' DEBUG" может оказаться очень полезной
# при отладке больших и сложных скриптов,
# когда размещение множества инструкций "echo $variable"
# может потребовать достаточно большого времени.

# Спасибо Stephane Chazelas.

exit 0
</pre>
                  </div>
                  <br>
                  <br>
                </td>
              </tr>
            </tbody></table>
          </div>

          <div class="NOTE">
            <table class="NOTE" width="100%" border="0">
              <tbody><tr>
                <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                <td align="left" valign="top">
                  <p>Конструкция <code class="USERINPUT"><strong>trap ''
                  SIGNAL</strong></code> (две одиночных кавычки) --
                  запрещает SIGNAL для оставшейся части сценария.
                  Конструкция <code class="USERINPUT"><strong>trap SIGNAL</strong></code>
                  -- восстанавливает действие сигнала SIGNAL. Эти
                  конструкции могут использоваться для защиты
                  критических участков сценария от нежелательного
                  прерывания.</p>
                </td>
              </tr>
            </tbody></table>
          </div>
<pre class="PROGRAMLISTING">       trap '' 2  # Сигнал 2 (Control-C) -- запрещен.
        command
        command
        command
        trap 2     # Разрешение реакции на Control-C
       
</pre>
          <br>
          <br>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="OPTIONS"></a>Глава 30. Необязательные параметры
          (ключи)</h1>

          <p><a name="OPTIONSREF"></a></p>

          <p>Необязательные параметры -- это дополнительные ключи
          (опции), которые оказывают влияние на поведение сценария
          и/или командной оболочки.</p>

          <p>Команда <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SETREF">set</a> позволяет задавать дополнительные
          опции прямо внутри сценария. В том месте сценария, где
          необходимо, чтобы та или иная опция вступила в силу, вставьте
          такую конструкцию <strong class="COMMAND">set -o option-name</strong>, или в более
          короткой форме -- <strong class="COMMAND">set -option-abbrev</strong>. Эти две формы
          записи совершенно идентичны по своему действию.</p>
<pre class="PROGRAMLISTING">      #!/bin/bash

      set -o verbose
      # Вывод команд перед их исполнением.
     
</pre>
          <br>
          <br>
<pre class="PROGRAMLISTING">      #!/bin/bash

      set -v
      # Имеет тот же эффект, что и выше.
     
</pre>
          <br>
          <br>

          <div class="NOTE">
            <table class="NOTE" width="100%" border="0">
              <tbody><tr>
                <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                <td align="left" valign="top">
                  <p>Для того, чтобы отключить действие той или иной
                  опции, следует вставить конструкцию <strong class="COMMAND">set +o option-name</strong>, или
                  <strong class="COMMAND">set +option-abbrev</strong>.</p>
                </td>
              </tr>
            </tbody></table>
          </div>
<pre class="PROGRAMLISTING">      #!/bin/bash

      set -o verbose
      # Вывод команд перед их исполнением.
      command
      ...
      command

      set +o verbose
      # Запретить вывод команд перед их исполнением.
      command
      # команда не выводится.


      set -v
      # Вывод команд перед их исполнением.
      command
      ...
      command

      set +v
      # Запретить вывод команд перед их исполнением.
      command

      exit 0
     
</pre>
          <br>
          <br>

          <p>Как вариант установки опций, можно предложить указывать их
          в заголовке сценария (в строке sha-bang) -- <code class="REPLACEABLE"><em>#!</em></code>.</p>
<pre class="PROGRAMLISTING">      #!/bin/bash -x
      #
      # Далее следует текст сценария.
     
</pre>
          <br>
          <br>

          <p><a name="INVOCATIONOPTIONSREF"></a></p>

          <p>Так же можно указывать дополнительные ключи в командной
          строке, при запуске сценария. Некоторые из опций работают
          только если они заданы из командной строки, например <code class="REPLACEABLE"><em>-i</em></code> -- ключ интерактивного
          режима работы скрипта.</p>

          <p><code class="USERINPUT"><strong>bash -v
          script-name</strong></code></p>

          <p><code class="USERINPUT"><strong>bash -o verbose
          script-name</strong></code></p>

          <p>Ниже приводится список некоторых полезных опций, которые
          могут быть указаны как в полной форме так и в
          сокращенной.</p>

          <div class="TABLE">
            <a name="AEN13260"></a>

            <p><strong>Таблица 30-1. Ключи Bash</strong></p>

            <table border="1" class="CALSTABLE">
              <thead>
                <tr>
                  <th align="left" valign="top">Краткое имя</th>

                  <th align="left" valign="top">Полное имя</th>

                  <th align="left" valign="top">Описание</th>
                </tr>
              </thead>

              <tbody>
                <tr>
                  <td align="left" valign="top"><a name="NOCLOBBERREF"></a><code class="OPTION">-C</code></td>

                  <td align="left" valign="top">noclobber</td>

                  <td align="left" valign="top">Предотвращает перезапись файла в
                  операциях перенаправления вывода (не распространяется
                  на конвейеры (каналы) -- <span class="TOKEN">&gt;|</span>)</td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">-D</code></td>

                  <td align="left" valign="top">(нет)</td>

                  <td align="left" valign="top">Выводит список строк в двойных
                  кавычках, которым предшествует символ <span class="TOKEN">$</span>, сам сценарий не
                  исполняется</td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">-a</code></td>

                  <td align="left" valign="top">allexport</td>

                  <td align="left" valign="top">Экспорт всех, определенных в сценарии,
                  переменных</td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">-b</code></td>

                  <td align="left" valign="top">notify</td>

                  <td align="left" valign="top">Выводит уведомление по завершении
                  фоновой задачи (job) (довольно редко используется в
                  сценариях)</td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">-c ...</code></td>

                  <td align="left" valign="top">(нет)</td>

                  <td align="left" valign="top">Читает команды из <strong class="COMMAND">...</strong></td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">-f</code></td>

                  <td align="left" valign="top">noglob</td>

                  <td align="left" valign="top">Подстановка имен файлов (globbing)
                  запрещена</td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">-i</code></td>

                  <td align="left" valign="top">interactive</td>

                  <td align="left" valign="top">Сценарий запускается в <span class="emphasis"><em class="EMPHASIS">интерактивном</em></span>
                  режиме</td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">-p</code></td>

                  <td align="left" valign="top">privileged</td>

                  <td align="left" valign="top">Сценарий запускается как <span class="QUOTE">"suid"</span>
                  (осторожно!)</td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">-r</code></td>

                  <td align="left" valign="top">restricted</td>

                  <td align="left" valign="top">Сценарий запускается в <span class="emphasis"><em class="EMPHASIS">ограниченном</em></span> режиме
                  (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RESTRICTED-SH">Глава 20</a>).</td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">-u</code></td>

                  <td align="left" valign="top">nounset</td>

                  <td align="left" valign="top">При попытке обращения к неопределенным
                  переменным, выдает сообщение об ошибке и прерывает
                  работу сценария</td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">-v</code></td>

                  <td align="left" valign="top">verbose</td>

                  <td align="left" valign="top">Выводит на <code class="FILENAME">stdout</code> каждую команду прежде,
                  чем она будет исполнена</td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">-x</code></td>

                  <td align="left" valign="top">xtrace</td>

                  <td align="left" valign="top">Подобна <code class="OPTION">-v</code>, но выполняет подстановку
                  команд</td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">-e</code></td>

                  <td align="left" valign="top">errexit</td>

                  <td align="left" valign="top">Прерывает работу сценария при появлении
                  первой же ошибки (когда команда возвращает ненулевой
                  код завершения)</td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">-n</code></td>

                  <td align="left" valign="top">noexec</td>

                  <td align="left" valign="top">Читает команды из сценария, но не
                  исполняет их (проверка синтаксиса)</td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">-s</code></td>

                  <td align="left" valign="top">stdin</td>

                  <td align="left" valign="top">Читает команды с устройства <code class="FILENAME">stdin</code></td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">-t</code></td>

                  <td align="left" valign="top">(нет)</td>

                  <td align="left" valign="top">Выход после исполнения первой
                  команды</td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">-</code></td>

                  <td align="left" valign="top">(нет)</td>

                  <td align="left" valign="top">Конец списка ключей (опций),
                  последующие аргументы будут восприниматься как <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#POSPARAMREF">позиционные параметры</a>.</td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">--</code></td>

                  <td align="left" valign="top">(нет)</td>

                  <td align="left" valign="top">Эквивалент предыдущей опции (-).</td>
                </tr>
              </tbody>
            </table>
          </div>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="GOTCHAS"></a>Глава 31. Широко распространенные
          ошибки</h1>

          <table border="0" width="100%" cellspacing="0" cellpadding="0" class="EPIGRAPH">
            <tbody><tr>
              <td width="45%">&nbsp;</td>

              <td width="45%" align="left" valign="top">
                <p><em>Turandot: Gli enigmi sono tre, la morte
                una!</em></p>

                <p><em>Caleph: No, no! Gli enigmi sono tre, una la
                vita!</em></p>
              </td>
            </tr>

            <tr>
              <td width="45%">&nbsp;</td>

              <td width="45%" align="right" valign="top"><em><span class="ATTRIBUTION">Puccini</span></em></td>
            </tr>
          </tbody></table>

          <p>Использование зарезервированных слов и служебных символов
          в качестве имен переменных.</p>
<pre class="PROGRAMLISTING">case=value0       # Может вызвать проблемы.
23skidoo=value1   # Тоже самое.
# Имена переменных, начинающиеся с цифр, зарезервированы командной оболочкой.
# Если имя переменной начинается с символа подчеркивания: _23skidoo=value1, то это не считается ошибкой.

# Однако... если имя переменной состоит из единственного символа подчеркивания, то это ошибка.
_=25
echo $_           # $_  -- это внутренняя переменная.

xyz((!*=value2    # Вызывает серьезные проблемы.
</pre>
          <br>
          <br>

          <p>Использование дефиса, и других зарезервированных символов,
          в именах переменных.</p>
<pre class="PROGRAMLISTING">var-1=23
# Вместо такой записи используйте 'var_1'.
</pre>
          <br>
          <br>

          <p>Использование одинаковых имен для переменных и функций.
          Это делает сценарий трудным для понимания.</p>
<pre class="PROGRAMLISTING">do_something ()
{
  echo "Эта функция должна что-нибудь сделать с \"$1\"."
}

do_something=do_something

do_something do_something

# Все это будет работать правильно, но слишком уж запутанно.
</pre>
          <br>
          <br>

          <p><a name="WSBAD"></a>Использование лишних <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WHITESPACEREF">пробелов</a>. В отличие от других
          языков программирования, Bash весьма привередлив по отношению
          к пробелам.</p>
<pre class="PROGRAMLISTING">var1 = 23   # Правильный вариант: 'var1=23'.
# В вышеприведенной строке Bash будет трактовать "var1" как имя команды
# с аргументами "=" и "23".

let c = $a - $b   # Правильный вариант: 'let c=$a-$b' или 'let "c = $a - $b"'

if [ $a -le 5]    # Правильный вариант: if [ $a -le 5 ]
# if [ "$a" -le 5 ]   еще лучше.
# [[ $a -le 5 ]] тоже верно.
</pre>
          <br>
          <br>

          <p>Ошибочным является предположение о том, что
          неинициализированные переменные содержат <span class="QUOTE">"ноль"</span>. Неинициализированные
          переменные содержат <span class="QUOTE">"пустое"</span> (null) значение, а
          <span class="emphasis"><em class="EMPHASIS">не</em></span> ноль.</p>
<pre class="PROGRAMLISTING">#!/bin/bash

echo "uninitialized_var = $uninitialized_var"
# uninitialized_var =
</pre>
          <br>
          <br>

          <p>Часто программисты путают операторы сравнения <span class="emphasis"><em class="EMPHASIS">=</em></span> и <span class="emphasis"><em class="EMPHASIS">-eq</em></span>. Запомните, оператор <span class="emphasis"><em class="EMPHASIS">=</em></span> используется для сравнения
          строковых переменных, а <span class="emphasis"><em class="EMPHASIS">-eq</em></span> -- для сравнения целых
          чисел.</p>
<pre class="PROGRAMLISTING">if [ "$a" = 273 ]      # Как вы полагаете? $a -- это целое число или строка?
if [ "$a" -eq 273 ]    # Если $a -- целое число.

# Иногда, такого рода ошибка никак себя не проявляет.
# Однако...


a=273.0   # Не целое число.

if [ "$a" = 273 ]
then
  echo "Равны."
else
  echo "Не равны."
fi    # Не равны.

# тоже самое и для  a=" 273"  и  a="0273".


# Подобные проблемы возникают при использовании "-eq" со строковыми значениями.

if [ "$a" -eq 273.0 ]
then
  echo "a = $a'
fi  # Исполнение сценария прерывается по ошибке.
# test.sh: [: 273.0: integer expression expected
</pre>
          <br>
          <br>

          <p>Ошибки при сравнении <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ICOMPARISON1">целых чисел</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SCOMPARISON1">строковых значений</a>.</p>
<pre class="PROGRAMLISTING">#!/bin/bash
# bad-op.sh

number=1

while [ "$number" &lt; 5 ]    # Неверно! должно быть   while [ "number" -lt 5 ]
do
  echo -n "$number "
  let "number += 1"
done

# Этот сценарий генерирует сообщение об ошибке:
# bad-op.sh: 5: No such file or directory
</pre>
          <br>
          <br>

          <p>Иногда, в операциях проверки, с использованием квадратных
          скобок ([ ]), переменные необходимо брать в двойные кавычки.
          См. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#STRTEST">Пример 7-6</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REDIR2">Пример 16-4</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ARGLIST">Пример 9-6</a>.</p>

          <p>Иногда сценарий не в состоянии выполнить команду из-за
          нехватки прав доступа. Если пользователь не сможет запустить
          команду из командной строки, то эта команда не сможет быть
          запущена и из сценария. Попробуйте изменить атрибуты команды,
          возможно вам придется установить бит suid.</p>

          <p>Использование символа <strong class="COMMAND">-</strong> в качестве оператора
          перенаправления (каковым он не является) может приводить к
          неожиданным результатам.</p>
<pre class="PROGRAMLISTING">command1 2&gt; - | command2  # Попытка передать сообщения об ошибках команде command1 через конвейер...
#    ...не будет работать.

command1 2&gt;&amp; - | command2  # Так же бессмысленно.

Спасибо S.C.
</pre>
          <br>
          <br>

          <p>Использование функциональных особенностей Bash <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BASH2REF">версии 2</a> или выше, может привести к
          аварийному завершению сценария, работающему под управлением
          Bash версии 1.XX.</p>
<pre class="PROGRAMLISTING">#!/bin/bash

minimum_version=2
# Поскольку Chet Ramey постоянно развивает Bash,
# вам может потребоваться указать другую минимально допустимую версию $minimum_version=2.XX.
E_BAD_VERSION=80

if [ "$BASH_VERSION" \&lt; "$minimum_version" ]
then
  echo "Этот сценарий должен исполняться под управлением Bash, версии $minimum или выше."
  echo "Настоятельно рекомендуется обновиться."
  exit $E_BAD_VERSION
fi

...
</pre>
          <br>
          <br>

          <p>Использование специфических особенностей Bash может
          приводить к аварийному завершению сценария в Bourne shell
          (<code class="USERINPUT"><strong>#!/bin/sh</strong></code>). Как
          правило, в Linux дистрибутивах, <strong class="COMMAND">sh</strong> является псевдонимом <strong class="COMMAND">bash</strong>, но это не всегда верно для
          UNIX-систем вообще.</p>

          <p>Сценарий, в котором строки отделяются друг от друга в
          стиле MS-DOS (<code class="REPLACEABLE"><em>\r\n</em></code>), будет завершаться
          аварийно, поскольку комбинация <code class="USERINPUT"><strong>#!/bin/bash\r\n</strong></code>
          считается недопустимой. Исправить эту ошибку можно простым
          удалением символа \r из сценария.</p>
<pre class="PROGRAMLISTING">#!/bin/bash

echo "Начало"

unix2dos $0    # Сценарий переводит символы перевода строки в формат DOS.
chmod 755 $0   # Восстановление прав на запуск.
               # Команда 'unix2dos' удалит право на запуск из атрибутов файла.

./$0           # Попытка запустить себя самого.
               # Но это не сработает из-за того, что теперь строки отделяются
               # друг от друга в стиле DOS.

echo "Конец"

exit 0
</pre>
          <br>
          <br>

          <p>Сценарий, начинающийся с <code class="USERINPUT"><strong>#!/bin/sh</strong></code>, не может
          работать в режиме полной совместимости с Bash. Некоторые из
          специфических функций, присущих Bash, могут оказаться
          запрещенными к использованию. Сценарий, который требует
          полного доступа ко всем расширениям, имеющимся в Bash, должен
          начинаться строкой <code class="USERINPUT"><strong>#!/bin/bash</strong></code>.</p>

          <p>Сценарий не может <strong class="COMMAND">экспортировать</strong> переменные <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FORKREF">родительскому процессу</a> - оболочке. Здесь
          как в природе, потомок может унаследовать черты родителя, но
          не наооборот.</p>
<pre class="PROGRAMLISTING">WHATEVER=/home/bozo
export WHATEVER
exit 0
</pre>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <strong class="COMMAND">echo $WHATEVER</strong>

<code class="PROMPT">bash$</code>
</pre>
          Будьте уверены -- при выходе в командную строку переменная
          $WHATEVER останется неинициализированной. <br>
          <br>

          <p>Использование в подоболочке переменных с теми же именами,
          что и в родительской оболочке может не давать ожидаемого
          результата.</p>

          <div class="EXAMPLE">
            <a name="SUBPIT"></a>

            <p><strong>Пример 31-1. Западня в подоболочке</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Западня в подоболочке.

outer_variable=внешняя_переменная
echo
echo "outer_variable = $outer_variable"
echo

(
# Запуск в подоболочке

echo "внутри подоболочки outer_variable = $outer_variable"
inner_variable=внутренняя_переменная  # Инициализировать
echo "внутри подоболочки inner_variable = $inner_variable"
outer_variable=внутренняя_переменная  # Как думаете? Изменит внешнюю переменную?
echo "внутри подоболочки outer_variable = $outer_variable"

# Выход из подоболочки
)

echo
echo "за пределами подоболочки inner_variable = $inner_variable"  # Ничего не выводится.
echo "за пределами подоболочки outer_variable = $outer_variable"  # внешняя_переменная.
echo

exit 0
</pre>
          </div>

          <p><a name="BADREAD0"></a></p>

          <p>Передача вывода от <strong class="COMMAND">echo</strong> по <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PIPEREF">конвейеру</a> команде <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#READREF">read</a> может давать неожиданные
          результаты. В этом сценарии, команда <strong class="COMMAND">read</strong> действует так, как будто бы
          она была запущена в подоболочке. Вместо нее лучше
          использовать команду <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SETREF">set</a> (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SETPOS">Пример 11-14</a>).</p>

          <div class="EXAMPLE">
            <a name="BADREAD"></a>

            <p><strong>Пример 31-2. Передача вывода от команды echo
            команде read, по конвейеру</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
#  badread.sh:
#  Попытка использования 'echo' и 'read'
#+ для записи значений в переменные.

a=aaa
b=bbb
c=ccc

echo "один два три" | read a b c
# Попытка записать значения в переменные a, b и c.

echo
echo "a = $a"  # a = aaa
echo "b = $b"  # b = bbb
echo "c = $c"  # c = ccc
# Присваивания не произошло.

# ------------------------------

# Альтернативный вариант.

var=`echo "один два три"`
set -- $var
a=$1; b=$2; c=$3

echo "-------"
echo "a = $a"  # a = один
echo "b = $b"  # b = два
echo "c = $c"  # c = три
# На этот раз все в порядке.

# ------------------------------

#  Обратите внимание: в подоболочке 'read', для первого варианта, переменные присваиваются нормально.
#  Но только в подоболочке.

a=aaa          # Все сначала.
b=bbb
c=ccc

echo; echo
echo "один два три" | ( read a b c;
echo "Внутри подоболочки: "; echo "a = $a"; echo "b = $b"; echo "c = $c" )
# a = один
# b = два
# c = три
echo "-------"
echo "Снаружи: "
echo "a = $a"  # a = aaa
echo "b = $b"  # b = bbb
echo "c = $c"  # c = ccc
echo

exit 0
</pre>
          </div>

          <p>Огромный риск, для безопасности системы, представляет
          использование в скриптах команд, с установленным битом <span class="QUOTE">"suid"</span>. <a name="AEN13453" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN13453"><span class="footnote">[61]</span></a></p>

          <p>Использование сценариев в качестве CGI-приложений может
          приводить к серьезным проблемам из-за отсутствия контроля
          типов переменных. Более того, они легко могут быть заменены
          взломщиком на его собственные сценарии.</p>

          <p>Bash не совсем корректно обрабатывает строки, содержащие
          двойной слэш (<span class="TOKEN">//</span>).</p>

          <p>Сценарии на языке Bash, созданные для Linux или BSD
          систем, могут потребовать доработки, перед тем как они смогут
          быть запущены в коммерческой версии UNIX. Такие сценарии, как
          правило, используют GNU-версии команд и утилит, которые имеют
          лучшую функциональность, нежели их аналоги в UNIX. Это
          особенно справедливо для таких утилит обработки текста, как
          <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TRREF">tr</a>.</p>

          <table border="0" width="100%" cellspacing="0" cellpadding="0" class="EPIGRAPH">
            <tbody><tr>
              <td width="45%">&nbsp;</td>

              <td width="45%" align="left" valign="top">
                <p><em>Danger is near thee --</em></p>

                <p><em>Beware, beware, beware, beware.</em></p>

                <p><em>Many brave hearts are asleep in the
                deep.</em></p>

                <p><em>So beware --</em></p>

                <p><em>Beware.</em></p>
              </td>
            </tr>

            <tr>
              <td width="45%">&nbsp;</td>

              <td width="45%" align="right" valign="top"><em><span class="ATTRIBUTION">A.J. Lamb and H.W.
              Petrie</span></em></td>
            </tr>
          </tbody></table>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="SCRSTYLE"></a>Глава 32. Стиль программирования</h1>

          <p>Возьмите в привычку структурный и систематический подход к
          программированию на языке командной оболочки. Даже для
          сценариев <span class="QUOTE">"выходного дня"</span> и <span class="QUOTE">"писаных на коленке"</span>, не
          поленитесь, найдите время для того, чтобы разложить свои
          мысли по полочкам и продумать структуру будущего скрипта
          прежде чем приниматься за кодирование.</p>

          <p>Ниже приводится несколько рекомендаций по оформлению
          сценариев, однако их не следует рассматривать как <span class="emphasis"><em class="EMPHASIS">Официальное Руководство</em></span>.</p>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="UNOFFICIALST"></a>32.1. Неофициальные рекомендации
            по оформлению сценариев</h2>

            <ul>
              <li>
                <p>Комментируйте свой код. Это сделает ваши сценарии
                понятнее для других, и более простыми, в обслуживании,
                для вас.</p>
<pre class="PROGRAMLISTING">PASS="$PASS${MATRIX:$(($RANDOM%${#MATRIX})):1}"
# Эта строка имела некоторый смысл в момент написания,
# но через год-другой будет очень тяжело вспомнить -- что она делает.
# (Из сценария "pw.sh", автор: Antek Sawicki)
</pre>
                <br>
                <br>

                <p>Добавляйте заголовочные комментарии в начале
                сценария и перед функциями.</p>
<pre class="PROGRAMLISTING">#!/bin/bash

#************************************************#
#                   xyz.sh                       #
#             автор: Bozo Bozeman                #
#                Июль 05, 2001                   #
#                                                #
#          Удаление файлов проекта.              #
#************************************************#

BADDIR=65                       # Нет такого каталога.
projectdir=/home/bozo/projects  # Каталог проекта.

# ------------------------------------------------------- #
# cleanup_pfiles ()                                       #
# Удаляет все файлы в заданном каталоге.                  #
# Параметры: $target_directory                            #
# Возвращаемое значение: 0 -- в случае успеха,            #
#                        $BADDIR -- в случае ошибки.      #
# ------------------------------------------------------- #
cleanup_pfiles ()
{
  if [ ! -d "$1" ]  # Проверка существования заданного каталога.
  then
    echo "$1 -- не является каталогом."
    return $BADDIR
  fi

  rm -f "$1"/*
  return 0   # Успешное завершение функции.
}

cleanup_pfiles $projectdir

exit 0
</pre>
                Не забывайте начинать ваш сценарий с sha-bang -- <span class="emphasis"><em class="EMPHASIS">#!/bin/bash</em></span>.<br>
                <br>
              </li>

              <li>
                <p>Заменяйте повторяющиеся значения константами. Это
                сделает ваш сценарий более простым для понимания и
                позволит вносить изменения, не опасаясь за его
                работоспособность.</p>
<pre class="PROGRAMLISTING">if [ -f /var/log/messages ]
then
  ...
fi
# Представьте себе, что через пару лет
# вы захотите изменить /var/log/messages на /var/log/syslog.
# Тогда вам придется отыскать все строки,
# содержащие /var/log/messages, и заменить их на /var/log/syslog.
# И проверить несколько раз -- не пропустили ли что-нибудь.

# Использование "констант" дает лучший способ:
LOGFILE=/var/log/messages  # Если и придется изменить, то только в этой строке.
if [ -f "$LOGFILE" ]
then
  ...
fi
</pre>
                <br>
                <br>
              </li>

              <li>
                <p>В качестве имен переменных и функций выбирайте
                осмысленные названия.</p>
<pre class="PROGRAMLISTING">fl=`ls -al $dirname`                 # Не очень удачное имя переменной.
file_listing=`ls -al $dirname`       # Уже лучше.


MAXVAL=10   # Пишите имена констант в верхнем регистре.
while [ "$index" -le "$MAXVAL" ]
...


E_NOTFOUND=75                        # Имена кодов ошибок -- в верхнем регистре,
                                     # к тому же, их желательно дополнять префиксом "E_".
if [ ! -e "$filename" ]
then
  echo "Файл $filename не найден."
  exit $E_NOTFOUND
fi


MAIL_DIRECTORY=/var/spool/mail/bozo  # Имена переменных окружения
                                     # так же желательно записывать символами
                                     # в верхнем регистре.
export MAIL_DIRECTORY


GetAnswer ()                         # Смешивание символов верхнего и нижнего решистров
                                     # удобно использовать для имен функций.
{
  prompt=$1
  echo -n $prompt
  read answer
  return $answer
}

GetAnswer "Ваше любимое число? "
favorite_number=$?
echo $favorite_number


_uservariable=23                     # Допустимо, но не рекомендуется.
# Желательно, чтобы пользовательские переменные не начинались с символа подчеркивания.
# Так обычно начинаются системные переменные.
</pre>
                <br>
                <br>
              </li>

              <li>
                <p>Используйте смысловые имена для <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXITCOMMANDREF">кодов завершения</a>.</p>
<pre class="PROGRAMLISTING">E_WRONG_ARGS=65
...
...
exit $E_WRONG_ARGS
</pre>
                См. так же <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXITCODES">Приложение C</a>.<br>
                <br>
              </li>

              <li>
                <p>Разделяйте большие сложные сценарии на серию более
                коротких и простых модулей. Пользуйтесь функциями. См.
                <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX79">Пример 34-4</a>.</p>
              </li>

              <li>
                <p>Не пользуйтесь сложными конструкциями, если их можно
                заменить простыми.</p>
<pre class="PROGRAMLISTING">COMMAND
if [ $? -eq 0 ]
...
# Избыточно и неинтуитивно.

if COMMAND
...
# Более понятно и коротко.
</pre>
                <br>
                <br>
              </li>
            </ul>

            <table border="0" width="100%" cellspacing="0" cellpadding="0" class="EPIGRAPH">
              <tbody><tr>
                <td width="45%">&nbsp;</td>

                <td width="45%" align="left" valign="top">
                  <p><em>... читая исходные тексты сценариев на Bourne
                  shell (/bin/sh). Я был потрясен тем, насколько
                  непонятно и загадочно могут выглядеть очень простые
                  алгоритмы из-за неправильного оформления кода. Я не
                  раз спрашивал себя: <span class="QUOTE">"Неужели кто-то может гордиться
                  таким кодом?"</span></em></p>
                </td>
              </tr>

              <tr>
                <td width="45%">&nbsp;</td>

                <td width="45%" align="right" valign="top"><em><span class="ATTRIBUTION">Landon Noll</span></em></td>
              </tr>
            </tbody></table>
          </div>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="MISCELLANY"></a>Глава 33. Разное</h1>

          <table border="0" width="100%" cellspacing="0" cellpadding="0" class="EPIGRAPH">
            <tbody><tr>
              <td width="45%">&nbsp;</td>

              <td width="45%" align="left" valign="top">
                <p><em>Практически никто не знает грамматики Bourne
                shell-а. Даже изучение исходных текстов не дает ее
                полного понимания.</em></p>
              </td>
            </tr>

            <tr>
              <td width="45%">&nbsp;</td>

              <td width="45%" align="right" valign="top"><em><span class="ATTRIBUTION">Tom Duff</span></em></td>
            </tr>
          </tbody></table>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="INTANDNONINT"></a>33.1. Интерактивный и
            неинтерактивный режим работы</h2>

            <p>В <span class="emphasis"><em class="EMPHASIS">интеракивном</em></span> режиме, оболочка
            читает команды, вводимые пользователем, с устройства <code class="FILENAME">tty</code>. Кроме того, такая оболочка
            считывает конфигурационные файлы на запуске, выводит строку
            приглашения к вводу (prompt), и, по-умолчанию, разрешает
            управление заданиями. Пользователь имеет возможность <span class="emphasis"><em class="EMPHASIS">взаимодействия</em></span> с
            оболочкой.</p>

            <p>Сценарий всегда запускается в неинтерактивном режиме.
            Но, не смотря на это, он сохраняет доступ к своему <code class="FILENAME">tty</code>. И даже может эмулировать
            интерактивный режим работы.</p>
<pre class="PROGRAMLISTING">#!/bin/bash
MY_PROMPT='$ '
while :
do
  echo -n "$MY_PROMPT"
  read line
  eval "$line"
  done

exit 0

# Этот сценарий, как иллюстрация к вышесказанному, предоставлен
# Stephane Chazelas (спасибо).
</pre>
            <br>
            <br>

            <p>Будем считать <span class="emphasis"><em class="EMPHASIS">интерактивным</em></span> такой сценарий,
            который может принимать ввод от пользователя, обычно с
            помощью команды <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#READREF">read</a> (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX36">Пример 11-2</a>). В <span class="QUOTE">"реальной жизни"</span> все
            намного сложнее. Пока же, будем придерживаться
            предположения о том, что интерактивный сценарий ограничен
            рамками tty, с которого сценарий был запущен
            пользователемa, т.е консоль или окно xterm.</p>

            <p>Сценарии начальной инициализации системы не являются
            интерактивными, поскольку они не предполагают вмешательство
            человека в процессе своей работы. Большая часть сценариев,
            выполняющих администрирование и обслуживание системы -- так
            же работают в неинтерактивном режиме. Многие задачи
            автоматизации труда администратора очень трудно представить
            себе без неинтерактивных сценариев.</p>

            <p>Неинтерактивные сценарии прекрасно могут работать в
            фоне, в то время, как интерактивные -- подвисают,
            останавливаясь на операциях, ожидающих ввода пользователя.
            Сложности, возникающие с запуском интерактивных сценариев в
            фоновом режиме, могут быть преодолены с помощью <strong class="COMMAND">expect</strong>-сценария или <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#HEREDOCREF">встроенного документа</a>. В простейших
            случаях, можно организовать перенаправление ввода из файла
            в команду <strong class="COMMAND">read</strong> (<strong class="COMMAND">read variable &lt;file</strong>). Эти
            приемы позволят создавать сценарии, которые смогут работать
            как в интерактивном, так и в неинтерактивном режимах.</p>

            <p>Если внутри сценария необходимо проверить режим работы
            -- интерактивный или неинтерактивный, это можно сделать
            проверкой переменной окружения <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PS1REF">$PS1</a>.</p>
<pre class="PROGRAMLISTING">if [ -z $PS1 ] # интерактивный режим?
then
  # неинтерактивный
  ...
else
  # интерактивный
  ...
fi
</pre>
            <a name="IITEST"></a>Еще один способ -- проверка установки
            флага <span class="QUOTE">"i"</span> в переменной <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FLPREF">$-</a>. 
<pre class="PROGRAMLISTING">case $- in
*i*)    # интерактивный режим
;;
*)      # неинтерактивный режим
;;
# (Из "UNIX F.A.Q.," 1993)
</pre>
            <br>
            <br>

            <div class="NOTE">
              <table class="NOTE" width="100%" border="0">
                <tbody><tr>
                  <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                  <td align="left" valign="top">
                    <p>Сценарий может принудительно запускаться в
                    интерактивном режиме, для этого необходимо указать
                    ключ <span class="TOKEN">-i</span> в строке-заголовке <code class="USERINPUT"><strong>#!/bin/bash
                    -i</strong></code>. Однако вы должны помнить о том,
                    что в таких случаях сценарий может выдавать
                    сообщения об ошибках даже тогда, когда ошибок, по
                    сути, нет.</p>
                  </td>
                </tr>
              </tbody></table>
            </div>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="WRAPPER"></a>33.2. Сценарии-обертки</h2>

            <p><a name="SHWRAPPER"></a></p>

            <p><span class="QUOTE">"Обертки"</span> -- это сценарии,
            которые содержат один или несколько вызовов системных
            команд или утилит, с длинным списком параметров. Такой
            прием освобождает пользователя от необходимости вводить
            вручную сложные и длинные команды из командной строки. Он
            особенно полезен при работе с <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SEDREF">sed</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AWKREF">awk</a>.</p>

            <p>Сценарии <strong class="COMMAND">sed</strong> или <strong class="COMMAND">awk</strong>, как правило вызываются в
            форме: <code class="USERINPUT"><strong>sed -e <code class="REPLACEABLE"><em>'commands'</em></code></strong></code>
            или <code class="USERINPUT"><strong>awk <code class="REPLACEABLE"><em>'commands'</em></code></strong></code>.
            "Заворачивая" такие вызовы в сценарий на языке
            командной оболочки, мы делаем их использование более
            простым для конечного пользователя. Кроме того, этот прием
            позволяет комбинировать вызовы <strong class="COMMAND">sed</strong> и <strong class="COMMAND">awk</strong>, например в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PIPEREF">конвейере</a>, позволяя передавать данные
            с выхода одной утилиты на вход другой.</p>

            <div class="EXAMPLE">
              <a name="EX3"></a>

              <p><strong>Пример 33-1. сценарий-обертка</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# Этот простой сценарий удаляет пустые строки из текстового файла.
# Проверка входных аргументов не производится.
#
# Однако вы можете дополнить сценарий такой проверкой,
# добавив нечто подобное:
# if [ -z "$1" ]
# then
#  echo "Порядок использования: `basename $0` текстовый_файл"
#  exit 65
# fi

# Для выполнения этих же действий,
# из командной строки можно набрать
#    sed -e '/^$/d' filename


sed -e /^$/d "$1"
#  '-e' -- означает команду "editing" (правка), за которой следуют необязательные параметры.
#  '^' -- с начала строки, '$' -- до ее конца.
#  Что соответствует строкам, которые не содержат символов между началом и концом строки,
#+ т.е. -- пустым строкам.
#  'd' -- команда "delete" (удалить).

#  Использование кавычек дает возможность
#+ обрабатывать файлы, чьи имена содержат пробелы.

exit 0
</pre>
            </div>

            <div class="EXAMPLE">
              <a name="EX4"></a>

              <p><strong>Пример 33-2. Более сложный пример
              сценария-обертки</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# "subst", Сценарий замены по шаблону
# т.е., "subst Smith Jones letter.txt".

ARGS=3
E_BADARGS=65   # Неверное число аргументов.

if [ $# -ne "$ARGS" ]
# Проверка числа аргументов.
then
  echo "Проядок использования: `basename $0` old-pattern new-pattern filename"
  exit $E_BADARGS
fi

old_pattern=$1
new_pattern=$2

if [ -f "$3" ]
then
    file_name=$3
else
    echo "Файл \"$3\" не найден."
    exit $E_BADARGS
fi

# Здесь, собственно, выполняется сама работа по поиску и замене.
sed -e "s/$old_pattern/$new_pattern/g" $file_name
# 's' -- команда "substitute" (замены),
# а /pattern/ -- задает шаблон искомого текста.
# "g" -- флаг "global" (всеобщий), означает "выполнить подстановку для *каждого*
# обнаруженного $old_pattern во всех строках, а не только в первой строке.

exit 0    # При успешном завершении сценария -- вернуть 0.
</pre>
            </div>

            <div class="EXAMPLE">
              <a name="COLTOTALER"></a>

              <p><strong>Пример 33-3. Сценарий-обертка вокруг сценария
              awk</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# Суммирует числа в заданном столбце из заданного файла.

ARGS=2
E_WRONGARGS=65

if [ $# -ne "$ARGS" ] # Проверка числа аргументов.
then
   echo "Порядок использования: `basename $0` имя_файла номер_столбца"
   exit $E_WRONGARGS
fi

filename=$1
column_number=$2

# Здесь используется прием передачи переменных
# из командной оболочки в сценарий awk .

# Многострочный сценарий awk должен записываться в виде:   awk ' ..... '


# Начало awk-сценария.
# -----------------------------
awk '

{ total += $'"${column_number}"'
}
END {
     print total
}

' "$filename"
# -----------------------------
# Конец awk-сценария.


#   С точки зрения безопасности, передача shell-переменных
#   во встроенный awk-скрипт, потенциально опасна,
#   поэтому, Stephane Chazelas предлагает следующую альтернативу:
#   ---------------------------------------
#   awk -v column_number="$column_number" '
#   { total += $column_number
#   }
#   END {
#       print total
#   }' "$filename"
#   ---------------------------------------


exit 0
</pre>
            </div>

            <p><a name="PERLREF"></a>Для сценариев, которые должны строиться
            по принципу швейцарского армейского ножа -- "все в
            одном", можно порекомендовать Perl. Perl совмещает в
            себе мощь и гибкость <strong class="COMMAND">sed</strong>, <strong class="COMMAND">awk</strong> и языка программирования
            <strong class="COMMAND">C</strong>. Он поддерживает модульность и
            объектно-ориентированный стиль программирования. Короткие
            сценарии Perl могут легко встраиваться в сценарии командной
            оболочки, и даже полностью заменить из (хотя автор весьма
            скептически относится к последнему утверждению).</p>

            <div class="EXAMPLE">
              <a name="EX56"></a>

              <p><strong>Пример 33-4. Сценарий на языке Perl,
              встроенный в Bash-скрипт</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# Это команды shell, предшествующий сценарию на Perl.
echo "Эта строка выводится средствами Bash, перед выполнением встроенного Perl-скрипта, в \"$0\"."
echo "=============================================================================================="

perl -e 'print "Эта строка выводится средствами Perl.\n";'
# Подобно sed, Perl тоже использует ключ "-e".

echo "====================================="

exit 0
</pre>
            </div>

            <p>Допускается даже комбинирование сценариев на Bash и на
            Perl, в пределах одного файла. В зависимости от того, какая
            часть сценария должна исполняться, сценарий вызывается с
            указанием требуемого интерпретатора.</p>

            <div class="EXAMPLE">
              <a name="BASHANDPERL"></a>

              <p><strong>Пример 33-5. Комбинирование сценария Bash и
              Perl в одном файле</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# bashandperl.sh

echo "Вас приветствует часть сценария, написанная на Bash."
# Далее могут следовать другие команды Bash.

exit 0
# Конец сценария на Bash.

# =======================================================

#!/usr/bin/perl
# Эта часть сценария должна вызываться с ключом -x.

print "Вас приветствует часть сценария, написанная на Perl.\n";
# Далее могут следовать другие команды Perl.

# Конец сценария на Perl.
</pre>
            </div>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>bash bashandperl.sh</strong></code>
<code class="COMPUTEROUTPUT">Вас приветствует часть сценария, написанная на Bash.</code>


<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>perl -x bashandperl.sh</strong></code>
<code class="COMPUTEROUTPUT">Вас приветствует часть сценария, написанная на Perl.</code>
             
</pre>
            <br>
            <br>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="TESTSANDCOMPARISONS"></a>33.3. Операции сравнения:
            Альтернативные решения</h2>

            <p>Операции сравнения, выполняемые с помощью конструкции <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DBLBRACKETS">[[ ]]</a>, могут оказаться
            предпочтительнее, чем <code class="USERINPUT"><strong>[ ]</strong></code>. Аналогично,
            при сравнении чисел, в более выгодном свете представляется
            конструкция <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DBLPARENS">(( ))</a>.</p>
<pre class="PROGRAMLISTING">a=8

# Все, приведенные ниже, операции сравнения -- эквивалентны.
test "$a" -lt 16 &amp;&amp; echo "да, $a &lt; 16"         # "И-список"
/bin/test "$a" -lt 16 &amp;&amp; echo "да, $a &lt; 16"
[ "$a" -lt 16 ] &amp;&amp; echo "да, $a &lt; 16"
[[ $a -lt 16 ]] &amp;&amp; echo "да, $a &lt; 16"          # Внутри [[ ]] и (( )) переменные
(( a &lt; 16 )) &amp;&amp; echo "да, $a &lt; 16"             # не обязательно брать в кавычки.

city="New York"
# Опять же, все, приведенные ниже, операции -- эквивалентны.
test "$city" \&lt; Paris &amp;&amp; echo "Да, Paris больше, чем $city"  # В смысле ASCII-строк.
/bin/test "$city" \&lt; Paris &amp;&amp; echo "Да, Paris больше, чем $city"
[ "$city" \&lt; Paris ] &amp;&amp; echo "Да, Paris больше, чем $city"
[[ $city &lt; Paris ]] &amp;&amp; echo "Да, Paris больше, чем $city"    # Кавычки вокруг $city не обязательны.

# Спасибо S.C.
</pre>
            <br>
            <br>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="RECURSIONSCT"></a>33.4. Рекурсия</h2>

            <p>Может ли сценарий <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RECURSIONREF">рекурсивно</a> вызывать себя самого?
            Да, может!</p>

            <div class="EXAMPLE">
              <a name="RECURSE"></a>

              <p><strong>Пример 33-6. Сценарий (бесполезный), который
              вызывает себя сам</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# recurse.sh

#  Может ли сценарий вызвать себя сам?
#  Да, но есть ли в этом смысл?

RANGE=10
MAXVAL=9

i=$RANDOM
let "i %= $RANGE"  # Генерация псевдослучайного числа в диапазоне 0 .. $MAXVAL.

if [ "$i" -lt "$MAXVAL" ]
then
  echo "i = $i"
  ./$0             #  Сценарий запускает новый экземпляр себя самого.
fi                 #  если число $i больше или равно $MAXVAL.

#  Если конструкцию "if/then" заменить на цикл "while", то это вызовет определенные проблемы.
#  Объясните -- почему?.

exit 0
</pre>
            </div>

            <div class="EXAMPLE">
              <a name="PBOOK"></a>

              <p><strong>Пример 33-7. Сценарий имеющий практическую
              ценность), который вызывает себя сам</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# pb.sh: телефонная книга

# Автор: Rick Boivie
# используется с его разрешения.
# Дополнен автором документа.

MINARGS=1     # Сценарию должен быть передан, по меньшей мере, один аргумент.
DATAFILE=./phonebook
PROGNAME=$0
E_NOARGS=70   # Ошибка, нет аргументов.

if [ $# -lt $MINARGS ]; then
      echo "Порядок использования: "$PROGNAME" data"
      exit $E_NOARGS
fi


if [ $# -eq $MINARGS ]; then
      grep $1 "$DATAFILE"
else
      ( shift; "$PROGNAME" $* ) | grep $1
      # Рекурсивный вызов.
fi

exit 0        #  Сценарий завершает свою работу здесь.
              #  Далее следует пример файла телефонной книги
              #+ в котором не используются символы комментария.

# ------------------------------------------------------------------------
# Пример файла телефонной книги

John Doe        1555 Main St., Baltimore, MD 21228          (410) 222-3333
Mary Moe        9899 Jones Blvd., Warren, NH 03787          (603) 898-3232
Richard Roe     856 E. 7th St., New York, NY 10009          (212) 333-4567
Sam Roe         956 E. 8th St., New York, NY 10009          (212) 444-5678
Zoe Zenobia     4481 N. Baker St., San Franciso, SF 94338   (415) 501-1631
# ------------------------------------------------------------------------

$bash pb.sh Roe
Richard Roe     856 E. 7th St., New York, NY 10009          (212) 333-4567
Sam Roe         956 E. 8th St., New York, NY 10009          (212) 444-5678

$bash pb.sh Roe Sam
Sam Roe         956 E. 8th St., New York, NY 10009          (212) 444-5678

#  Если сценарию передаются несколько аргументов,
#+ то выводятся только те строки, которые содержат их все.
</pre>
            </div>

            <div class="CAUTION">
              <table class="CAUTION" width="100%" border="0">
                <tbody><tr>
                  <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                  <td align="left" valign="top">
                    <p>Слишком глубокая рекурсия может привести к
                    исчерпанию пространства, выделенного под стек, и
                    "вываливанию" сценария по
                    "segfault".</p>
                  </td>
                </tr>
              </tbody></table>
            </div>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="COLORIZING"></a>33.5. <span class="QUOTE">"Цветные"</span> сценарии</h2>

            <p>Для установки атрибутов отображения информации на
            экране, таких как: жирный текст, цвет символов, цвет фона и
            т.п., с давних пор используются ANSI <a name="AEN13625" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN13625"><span class="footnote">[62]</span></a>
            escape-последовательности. Эти последовательности широко
            используются в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DOSBATCH1">пакетных файлах DOS</a>, эти же
            последовательности используются и в сценариях Bash.</p>

            <div class="EXAMPLE">
              <a name="EX30A"></a>

              <p><strong>Пример 33-8. <span class="QUOTE">"Цветная"</span> адресная
              книга</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# ex30a.sh: Версия сценария ex30.sh, с добавлением цвета .
#           Грубый пример базы данных


clear                                   # Очистка экрана

echo -n "          "
echo -e '\E[37;44m'"\033[1mСписок\033[0m"
                                        # Белый текст на синем фоне
echo; echo
echo -e "\033[1mВыберите интересующую Вас персону:\033[0m"
                                        # Жирный шрифт
tput sgr0
echo "(Введите только первую букву имени.)"
echo
echo -en '\E[47;34m'"\033[1mE\033[0m"   # Синий
tput sgr0                               # сброс цвета
echo "vans, Roland"                     # "[E]vans, Roland"
echo -en '\E[47;35m'"\033[1mJ\033[0m"   # Пурпурный
tput sgr0
echo "ones, Mildred"
echo -en '\E[47;32m'"\033[1mS\033[0m"   # Зеленый
tput sgr0
echo "mith, Julie"
echo -en '\E[47;31m'"\033[1mZ\033[0m"   # Красный
tput sgr0
echo "ane, Morris"
echo

read person

case "$person" in
# Обратите внимание: переменная взята в кавычки.

  "E" | "e" )
  # Пользователь может ввести как заглавную, так и строчную букву.
  echo
  echo "Roland Evans"
  echo "4321 Floppy Dr."
  echo "Hardscrabble, CO 80753"
  echo "(303) 734-9874"
  echo "(303) 734-9892 fax"
  echo "revans@zzy.net"
  echo "Старый друг и партнер по бизнесу"
  ;;

  "J" | "j" )
  echo
  echo "Mildred Jones"
  echo "249 E. 7th St., Apt. 19"
  echo "New York, NY 10009"
  echo "(212) 533-2814"
  echo "(212) 533-9972 fax"
  echo "milliej@loisaida.com"
  echo "Подружка"
  echo "День рождения: 11 февраля"
  ;;

# Информация о Smith и Zane будет добавлена позднее.

          * )
   # Выбор по-умолчанию.
   # "Пустой" ввод тоже обрабатывается здесь.
   echo
   echo "Нет данных."
  ;;

esac

tput sgr0                               # Сброс цвета

echo

exit 0
</pre>
            </div>

            <p>Самая простая и, на мой взгляд, самая полезная
            escape-последовательность -- это "жирный текст",
            <strong class="COMMAND">\033[1m ... \033[0m</strong>. Здесь,
            комбинация <span class="TOKEN">\033</span> представляет <span class="emphasis"><em class="EMPHASIS">escape</em></span>-символ, кобинация
            <span class="QUOTE">"[1"</span> -- включает вывод
            жирным текстом, а <span class="QUOTE">"[0"</span> -- выключает. Символ
            <span class="QUOTE">"m"</span> -- завершает каждую из
            escape-последовательностей.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo -e "\033[1mЭто жирный текст.\033[0m"</strong></code>
             
</pre>
            <br>
            <br>

            <p>Простая escape-последовательность, которая управляет
            атрибутом подчеркивания (в <span class="emphasis"><em class="EMPHASIS">rxvt</em></span> и <span class="emphasis"><em class="EMPHASIS">aterm</em></span>).</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo -e "\033[4mЭто подчеркнутый текст.\033[0m"</strong></code>
             
</pre>
            <br>
            <br>

            <div class="NOTE">
              <table class="NOTE" width="100%" border="0">
                <tbody><tr>
                  <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                  <td align="left" valign="top">
                    <p>Ключ <code class="OPTION">-e</code>, в команде <strong class="COMMAND">echo</strong>, разрешает
                    интерпретацию escape-последовательностей.</p>
                  </td>
                </tr>
              </tbody></table>
            </div>

            <p>Другие escape-последовательности, изменяющие атрибуты
            цвета:</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo -e '\E[34;47mЭтот текст выводится синим цветом.'; tput sgr0</strong></code>


<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo -e '\E[33;44m'"желтый текст на синем фоне"; tput sgr0</strong></code>
             
</pre>
            Команда <strong class="COMMAND">tput sgr0</strong> возвращает настройки
            терминала в первоначальное состояние.<br>
            <br>

            <table class="SIDEBAR" border="1" cellpadding="5">
              <tbody><tr>
                <td>
                  <div class="SIDEBAR">
                    <a name="AEN13659"></a>

                    <p>Вывод цветного текста осуществляется по
                    следующему шаблону:.</p>

                    <p><code class="USERINPUT"><strong>echo -e
                    '\E[COLOR1;COLOR2mКакой либо
                    текст.'</strong></code></p>

                    <p>Где <span class="QUOTE">"\E["</span> -- начало
                    escape-последовательности. Числа <span class="QUOTE">"COLOR1"</span> и <span class="QUOTE">"COLOR2"</span>,
                    разделенные точкой с запятой, задают цвет символов
                    и цвет фона, в соответствии с таблицей цветов,
                    приведенной ниже. (Порядок указания цвета текста и
                    фона не имеет значения, поскольку диапазоны
                    числовых значений цвета для текста и фона не
                    пересекаются). Символ <span class="QUOTE">"m"</span> -- должен
                    завершать escape-последовательность.</p>

                    <p>Обратите внимание: <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SNGLQUO">одиночные кавычки</a> окружают
                    все, что следует за <strong class="COMMAND">echo -e</strong>.</p>
                  </div>
                </td>
              </tr>
            </tbody></table>

            <p>Числовые значения цвета, приведенные ниже, справедливы
            для <span class="emphasis"><em class="EMPHASIS">rxvt</em></span>. Для других эмуляторов
            они могут несколько отличаться.</p>

            <div class="TABLE">
              <a name="AEN13673"></a>

              <p><strong>Таблица 33-1. Числовые значения цвета в
              escape-последовательностях</strong></p>

              <table border="1" class="CALSTABLE">
                <thead>
                  <tr>
                    <th align="left" valign="top">Цвет</th>

                    <th align="left" valign="top">Текст</th>

                    <th align="left" valign="top">Фон</th>
                  </tr>
                </thead>

                <tbody>
                  <tr>
                    <td align="left" valign="top"><code class="OPTION">черный</code></td>

                    <td align="left" valign="top">30</td>

                    <td align="left" valign="top">40</td>
                  </tr>

                  <tr>
                    <td align="left" valign="top"><code class="OPTION">красный</code></td>

                    <td align="left" valign="top">31</td>

                    <td align="left" valign="top">41</td>
                  </tr>

                  <tr>
                    <td align="left" valign="top"><code class="OPTION">зеленый</code></td>

                    <td align="left" valign="top">32</td>

                    <td align="left" valign="top">42</td>
                  </tr>

                  <tr>
                    <td align="left" valign="top"><code class="OPTION">желтый</code></td>

                    <td align="left" valign="top">33</td>

                    <td align="left" valign="top">43</td>
                  </tr>

                  <tr>
                    <td align="left" valign="top"><code class="OPTION">синий</code></td>

                    <td align="left" valign="top">34</td>

                    <td align="left" valign="top">44</td>
                  </tr>

                  <tr>
                    <td align="left" valign="top"><code class="OPTION">пурпурный</code></td>

                    <td align="left" valign="top">35</td>

                    <td align="left" valign="top">45</td>
                  </tr>

                  <tr>
                    <td align="left" valign="top"><code class="OPTION">зеленовато-голубой</code></td>

                    <td align="left" valign="top">36</td>

                    <td align="left" valign="top">46</td>
                  </tr>

                  <tr>
                    <td align="left" valign="top"><code class="OPTION">белый</code></td>

                    <td align="left" valign="top">37</td>

                    <td align="left" valign="top">47</td>
                  </tr>
                </tbody>
              </table>
            </div>

            <div class="EXAMPLE">
              <a name="COLORECHO"></a>

              <p><strong>Пример 33-9. Вывод цветного
              текста</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# color-echo.sh: Вывод цветных сообщений.

black='\E[30;47m'
red='\E[31;47m'
green='\E[32;47m'
yellow='\E[33;47m'
blue='\E[34;47m'
magenta='\E[35;47m'
cyan='\E[36;47m'
white='\E[37;47m'


cecho ()                     # Color-echo.
                             # Аргумент $1 = текст сообщения
                             # Аргумент $2 = цвет
{
local default_msg="Нет сообщений."
                             # Не обязательно должна быть локальной.

message=${1:-$default_msg}   # Текст сообщения по-умолчанию.
color=${2:-$black}           # Цвет по-умолчанию черный.

  echo -e "$color"
  echo "$message"
  tput sgr0                  # Восстановление первоначальных настроек терминала.
  return
}


# Попробум что-нибудь вывести.
# ----------------------------------------------------
cecho "Синий текст..." $blue
cecho "Пурпурный текст." $magenta
cecho "Позеленевший от зависти." $green
cecho "Похоже на красный?" $red
cecho "Циан, более известный как цвет морской волны." $cyan
cecho "Цвет не задан (по-умолчанию черный)."
       # Аргумент $color отсутствует.
cecho "\"Пустой\" цвет (по-умолчанию черный)." ""
       # Передан "пустой" аргумент цвета.
cecho
       # Ни сообщение ни цвет не переданы.
cecho "" ""
       # Функции переданы "пустые" аргументы $message и $color.
# ----------------------------------------------------

echo

exit 0

# Упражнения:
# ---------
# 1) Добавьте в функцию 'cecho ()' возможность вывода "жирного текста".
# 2) Добавьте возможность управления цветом фона.
</pre>
            </div>

            <div class="CAUTION">
              <table class="CAUTION" width="100%" border="0">
                <tbody><tr>
                  <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                  <td align="left" valign="top">
                    <p>Однако, как обычно, в бочке меда есть ложка
                    дегтя. <span class="emphasis"><em class="EMPHASIS">Escape-последовательности ANSI
                    совершенно не переносимы</em></span>. Вывод в одном
                    эмуляторе терминала (или в консоли) может
                    разительно отличаться от вывода в другом эмуляторе.
                    <span class="QUOTE">"Расцвеченные"</span>
                    сценарии, дающие изумительно красивый вывод текста
                    на одном терминале, могут давать совершенно
                    нечитаемый текст на другом. Это ставит под сомнение
                    практическую ценность <span class="QUOTE">"расцвечивания"</span>
                    вывода в сценариях, низводя ее до уровня никчемной
                    <span class="QUOTE">"игрушки"</span>.</p>
                  </td>
                </tr>
              </tbody></table>
            </div>

            <p>Moshe Jacobson разработал утилиту <strong class="COMMAND">color</strong> (<!--noindex--><a href="http://runslinux.net/projects/color" target="_top">http://runslinux.net/projects/color</a><!--/noindex-->),
            которая значительно упрощает работу с ANSI
            escape-последовательностями, заменяя, только что
            обсуждавшиеся, неуклюжие конструкции, логичным и понятным
            синтаксисом.</p>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="OPTIMIZATIONS"></a>33.6. Оптимизация</h2>

            <p>По большей части, сценарии на языке командной оболочки,
            используются для быстрого решения несложных задач. Поэтому
            оптимизация сценариев, по скорости исполнения, не является
            насущной проблемой. Тем не менее, представьте себе
            ситуацию, когда сценарий, выполняющий довольно важную
            работу, в принципе справляется со своей задачей, но делает
            это очень медленно. Написание же аналогичной программы на
            языке компилирующего типа -- неприемлемо. Самое простое
            решение -- переписать самые медленные участки кода
            сценария. Возможно ли применить принципы оптимизации к
            сценарию на практике?</p>

            <p>Для начала проверьте все циклы в сценарии. Основная
            масса времени уходит на работу в циклах. Если это возможно,
            вынесите все ресурсоемкие операции за пределы циклов.</p>

            <p>Старайтесь использовать <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BUILTINREF">встроенные</a> команды. Они исполняются
            значительно быстрее и, как правило, не запускают
            подоболочку при вызове.</p>

            <p>Избегайте использования избыточных команд, особенно это
            относится к <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PIPEREF">конвейерам</a>.</p>
<pre class="PROGRAMLISTING">cat "$file" | grep "$word"

grep "$word" "$file"

#  Эти команды дают один и тот же результат,
#+ но вторая работает быстрее, поскольку запускает на один подпроцесс меньше.
</pre>
            Не следует злоупотреблять командой <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CATREF">cat</a>.<br>
            <br>

            <p>Для профилирования сценариев, можно воспользоваться
            командами <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TIMREF">time</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TIMESREF">times</a>. Не следует пренебрегать
            возможностью переписать особенно критичные участки кода на
            языке C или даже на ассемблере.</p>

            <p>Попробуйте минимизировать количество операций с файлами.
            Bash не "страдает" излишней эффективностью при
            работе с файлами, попробуйте применить специализированные
            средства для работы с файлами в сценариях, такие как <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AWKREF">awk</a> или <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PERLREF">Perl</a>.</p>

            <p>Записывайте сценарии в структурированной форме, это
            облегчит их последующую реорганизацию и оптимизацию.
            Помните, что значительная часть методов оптимизации кода,
            существующих в языках высокого уровня, вполне применима и к
            сценариям, однако есть и такие, которые не могут
            применяться. Основной критерий здесь -- это здравый
            смысл.</p>

            <p>Прекрасный пример того, как оптимизация может сократить
            время работы сценария, вы найдете в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MONTHLYPMT">Пример 12-32</a>.</p>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="ASSORTEDTIPS"></a>33.7. Разные советы</h2>

            <ul>
              <li>
                <p>Для ведения учета использования сценария
                пользователями, добавьте следующие строки в сценарий.
                Они запишут в файл отчета название сценария и время
                запуска.</p>
<pre class="PROGRAMLISTING"># Добавление (&gt;&gt;) учетной записи, об использовании сценария, в файл отчета.

date&gt;&gt; $SAVE_FILE      # Дата и время.
echo $0&gt;&gt; $SAVE_FILE   # Название сценария.
echo&gt;&gt; $SAVE_FILE      # Пустая строка -- как разделитель записей.

# Не забудьте определить переменную окружения SAVE_FILE в ~/.bashrc
# (что нибудь, типа: ~/.scripts-run)
</pre>
                <br>
                <br>
              </li>

              <li>
                <p><a name="PREPENDREF"></a></p>

                <p>Оператор <span class="TOKEN">&gt;&gt;</span> производит добавление
                строки в конец файла. А как быть, если надо добавить
                строку в начало существующего файла?</p>
<pre class="PROGRAMLISTING">file=data.txt
title="***Это титульная строка в текстовом файле***"

echo $title | cat - $file &gt;$file.new
# "cat -" объединяет stdout с содержимым $file.
#  В результате получится
#+ новый файл $file.new, в начало которого добавлена строка $title.
</pre>
                <br>
                <br>

                <p>Само собой разумеется, то же самое можно сделать с
                помощью <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SEDREF">sed</a>.</p>
              </li>

              <li>
                <p>Сценарий командной оболочки может использоваться как
                команда внутри другого сценария командной оболочки,
                <span class="emphasis"><em class="EMPHASIS">Tcl</em></span>, или <span class="emphasis"><em class="EMPHASIS">wish</em></span> сценария или, даже в
                <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MAKEFILEREF">Makefile</a>. Он может быть вызван
                как внешняя команда из программы на языке C, с помощью
                функции <code class="REPLACEABLE"><em>system()</em></code>, т.е. <code class="REPLACEABLE"><em>system("script_name");</em></code>.</p>
              </li>

              <li>
                <p>Собирайте свои библиотеки часто используемых функций
                и определений. Эти "библиотеки" могут быть
                <span class="QUOTE">"подключены"</span> к
                сценариям, с помощью команды <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DOTREF">точка</a> (<strong class="COMMAND">.</strong>) или <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SOURCEREF">source</a>.</p>
<pre class="PROGRAMLISTING"># Сценарий-библиотека
# ------ -------

# Обратите внимание:
# Здесь нет sha-bang ("#!").
# И нет "живого кода".


# Определения переменных

ROOT_UID=0             # UID root-а, 0.
E_NOTROOT=101          # Ошибка -- "обычный пользователь".
MAXRETVAL=255          # Максимальное значение, которое могут возвращать функции.
SUCCESS=0
FAILURE=-1



# Функции

Usage ()               # Сообщение "Порядок использования:".
{
  if [ -z "$1" ]       # Нет аргументов.
  then
    msg=filename
  else
    msg=$@
  fi

  echo "Порядок использования: `basename $0` "$msg""
}


Check_if_root ()       # Проверка прав пользователя.
{                      # из примера "ex39.sh".
  if [ "$UID" -ne "$ROOT_UID" ]
  then
    echo "Этот сценарий должен запускаться с привилегиями root."
    exit $E_NOTROOT
  fi
}


CreateTempfileName ()  # Создание "уникального" имени для временного файла.
{                      # Из примера "ex51.sh".
  prefix=temp
  suffix=`eval date +%s`
  Tempfilename=$prefix.$suffix
}


isalpha2 ()            # Проверка, состоит ли строка только из алфавитных символов.
{                      # Из примера "isalpha.sh".
  [ $# -eq 1 ] || return $FAILURE

  case $1 in
  *[!a-zA-Z]*|"") return $FAILURE;;
  *) return $SUCCESS;;
  esac                 # Спасибо S.C.
}


abs ()                           # Абсолютное значение.
{                                # Внимание: Максимально возможное возвращаеиое значение
                                 # не может превышать 255.
  E_ARGERR=-999999

  if [ -z "$1" ]                 # Проверка наличия входного аргумента.
  then
    return $E_ARGERR             # Код ошибки, обычно возвращаемый в таких случаях.
  fi

  if [ "$1" -ge 0 ]              # Если не отрицательное,
  then                           #
    absval=$1                    # оставить как есть.
  else                           # Иначе,
    let "absval = (( 0 - $1 ))"  # изменить знак.
  fi

  return $absval
}


tolower ()             #  Преобразование строк символов в нижний регистр
{

  if [ -z "$1" ]       #  Если нет входного аргумента,
  then                 #+ выдать сообщение об ошибке
    echo "(null)"
    return             #+ и выйти из функции.
  fi

  echo "$@" | tr A-Z a-z
  # Преобразовать все входные аргументы ($@).

  return

# Для записи результата работы функции в переменную, используйте операцию подстановки команды.
# Например:
#    oldvar="A seT of miXed-caSe LEtTerS"
#    newvar=`tolower "$oldvar"`
#    echo "$newvar"    # a set of mixed-case letters
#
# Упражнение: Добавьте в эту библиотеку функцию перевода символов в верхний регистр.
#           toupper()  [это довольно просто].
}
</pre>
                <br>
                <br>
              </li>

              <li>
                <p>Для повышения ясности комментариев, выделяйте их
                особым образом.</p>
<pre class="PROGRAMLISTING">## Внимание!
rm -rf *.zzy   ##  Комбинация ключей "-rf", в команде "rm", чрезвычайно опасна,
               ##+ особенно при удалении по шаблону.

#+ Продолжение комментария на новой строке.
#  Это первая строка комментария
#+ это вторая строка комментария,
#+ это последняя строка комментария.

#* Обратите внимание.

#o Элемент списка.

#&gt; Альтернативный вариант.
while [ "$var1" != "end" ]    #&gt; while test "$var1" != "end"
</pre>
                <br>
                <br>
              </li>

              <li>
                <p>Для создания блочных комментариев, можно
                использовать конструкцию <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TESTCONSTRUCTS1">if-test</a>.</p>
<pre class="PROGRAMLISTING">#!/bin/bash

COMMENT_BLOCK=
#  Если попробовать инициализировать эту переменную чем нибудь,
#+ то вы получите неожиданный результат.

if [ $COMMENT_BLOCK ]; then

Блок комментария --
=================================
Это строка комментария.
Это другая строка комментария.
Это еще одна строка комментария.
=================================

echo "Эта строка не выводится."

Этот блок комментария не вызывает сообщения об ошибке! Круто!

fi

echo "Эта строка будет выведена на stdout."

exit 0
</pre>
                <br>
                <br>

                <p>Сравните этот вариант создания блочных комментариев
                со <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CBLOCK1">встроенным документом, использующимся
                для создания блочных комментариев</a>.</p>
              </li>

              <li>
                <p>С помощью служебной переменной <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#XSTATVARREF">$?</a>, можно проверить --
                является ли входной аргумент целым числом.</p>
<pre class="PROGRAMLISTING">#!/bin/bash

SUCCESS=0
E_BADINPUT=65

test "$1" -ne 0 -o "$1" -eq 0 2&gt;/dev/null
# Проверка: "равно нулю или не равно нулю".
# 2&gt;/dev/null подавление вывода сообщений об ошибках.

if [ $? -ne "$SUCCESS" ]
then
  echo "Порядок использования: `basename $0` целое_число"
  exit $E_BADINPUT
fi

let "sum = $1 + 25"             # Будет выдавать ошибку, если $1 не является целым числом.
echo "Sum = $sum"

# Любая переменная может быть проверена таким образом, а не только входные аргументы.

exit 0
</pre>
                <br>
                <br>
              </li>

              <li>
                <p><a name="RVT"></a>Диапазон, возвращаемых функциями
                значений, 0 - 255 -- серьезное ограничение. Иногда
                может оказаться весьма проблематичным использование
                глобальных переменных, для передачи результата из
                функции. В таких случаях можно порекомендовать передачу
                результатов работы функции через запись в <code class="FILENAME">stdout</code>.</p>

                <div class="EXAMPLE">
                  <a name="MULTIPLICATION"></a>

                  <p><strong>Пример 33-10. Необычный способ передачи
                  возвращаемого значения</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# multiplication.sh

multiply ()                     # Функции выполняет перемножение всех переданых аргументов.
{
  local product=1

  until [ -z "$1" ]             # Пока не дошли до последнего аргумента...
  do
    let "product *= $1"
    shift
  done

  echo $product                 #  Значение не будет выведено на экран,
}                               #+ поскольку оно будет записано в переменную.

mult1=15383; mult2=25211
val1=`multiply $mult1 $mult2`
echo "$mult1 X $mult2 = $val1"
                                # 387820813

mult1=25; mult2=5; mult3=20
val2=`multiply $mult1 $mult2 $mult3`
echo "$mult1 X $mult2 X $mult3 = $val2"
                                # 2500

mult1=188; mult2=37; mult3=25; mult4=47
val3=`multiply $mult1 $mult2 $mult3 $mult4`
echo "$mult1 X $mult2 X $mult3 X mult4 = $val3"
                                # 8173300

exit 0
</pre>
                </div>

                <p>Такой прием срабатывает и для строковых значений.
                Таким образом, функция может <span class="QUOTE">"возвращать"</span> и
                нечисловой результат.</p>
<pre class="PROGRAMLISTING">capitalize_ichar ()          #  Первый символ всех строковых аргументов
{                            #+ переводится в верхний регистр.

  string0="$@"               # Принять все аргументы.

  firstchar=${string0:0:1}   # Первый символ.
  string1=${string0:1}       # Остаток строки.

  FirstChar=`echo "$firstchar" | tr a-z A-Z`
                             # Преобразовать в верхний регистр.

  echo "$FirstChar$string1"  # Выдать на stdout.

}

newstring=`capitalize_ichar "each sentence should start with a capital letter."`
echo "$newstring"          # Each sentence should start with a capital letter.
</pre>
                <br>
                <br>

                <p>Используя этот прием, функция может <span class="QUOTE">"возвращать"</span> даже
                несколько значений.</p>

                <div class="EXAMPLE">
                  <a name="SUMPRODUCT"></a>

                  <p><strong>Пример 33-11. Необычный способ получения
                  нескольких возвращаемых значений</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# sum-product.sh
# Функция может "возвращать" несколько значений.

sum_and_product ()   # Вычисляет сумму и произведение аргументов.
{
  echo $(( $1 + $2 )) $(( $1 * $2 ))
# Вывод на stdout двух значений, разделенных пробелом.
}

echo
echo "Первое число: "
read first

echo
echo "Второе число: "
read second
echo

retval=`sum_and_product $first $second`      # Получить результат.
sum=`echo "$retval" | awk '{print $1}'`      # Первое значение (поле).
product=`echo "$retval" | awk '{print $2}'`  # Второе значение (поле).

echo "$first + $second = $sum"
echo "$first * $second = $product"
echo

exit 0
</pre>
                </div>
              </li>

              <li>
                <p>Следующая хитрость -- передача <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ARRAYREF">массива</a> в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FUNCTIONREF">функцию</a>, и <span class="QUOTE">"возврат"</span> массива из
                функции.</p>

                <p>Передача массива в функцию выполняется посредством
                записи элементов массива, разделенных пробелами, в
                переменную, с помощью операции <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COMMANDSUBREF">подстановки команды</a>.
                Получить массив обратно можно, следуя вышеописанной
                стратегии, через вывод на stdout, а затем, с помощью
                все той же операции подстановки команды и оператора
                <strong class="COMMAND">( ... )</strong> -- записать в
                массив.</p>

                <div class="EXAMPLE">
                  <a name="ARRFUNC"></a>

                  <p><strong>Пример 33-12. Передача массива в функцию и
                  возврат массива из функции</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# array-function.sh: Передача массива в функцию и...
#                   "возврат" массива из функции


Pass_Array ()
{
  local passed_array   # Локальная переменная.
  passed_array=( `echo "$1"` )
  echo "${passed_array[@]}"
  #  Список всех элементов в новом массиве,
  #+ объявленном и инициализированном в функции.
}


original_array=( element1 element2 element3 element4 element5 )

echo
echo "original_array = ${original_array[@]}"
#                      Список всех элементов исходного массива.


# Так можно отдать массив в функцию.
# **********************************
argument=`echo ${original_array[@]}`
# **********************************
#  Поместив все элементы массива в переменную,
#+ разделяя их пробелами.
#
# Обратите внимание: метод прямой передачи массива в функцию не сработает.


# Так можно получить массив из функции.
# *****************************************
returned_array=( `Pass_Array "$argument"` )
# *****************************************
# Записать результат в переменную-массив.

echo "returned_array = ${returned_array[@]}"

echo "============================================================="

#  А теперь попробуйте получить доступ к локальному массиву
#+ за пределами функции.
Pass_Array "$argument"

# Функция выведет массив, но...
#+ доступ к локальному массиву, за пределами функции, окажется невозможен.
echo "Результирующий массив (внутри функции) = ${passed_array[@]}"
# "ПУСТОЕ" ЗНАЧЕНИЕ, поскольку это локальная переменная.

echo

exit 0
</pre>
                </div>

                <p>Более сложный пример передачи массивов в функции, вы
                найдете в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LIFESLOW">Пример A-11</a>.</p>
              </li>

              <li>
                <p>Использование конструкций с двойными круглыми
                скобками позволяет применять C-подобный синтаксис
                операций присвоения и инкремента переменных, а также
                оформления циклов <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FORLOOPREF1">for</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WHILELOOPREF">while</a>. См. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FORLOOPC">Пример 10-12</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WHLOOPC">Пример 10-17</a>.</p>
              </li>

              <li>
                <p>Иногда очень удобно "пропускать" данные
                через один и тот же фильтр, но с разными параметрами,
                используя конвейерную обработку. Особенно это относится
                к <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TRREF">tr</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GREPREF">grep</a>.</p>
<pre class="PROGRAMLISTING"># Из примера "wstrings.sh".

wlist=`strings "$1" | tr A-Z a-z | tr '[:space:]' Z | \
tr -cs '[:alpha:]' Z | tr -s '\173-\377' Z | tr Z ' '`
</pre>
                <br>
                <br>

                <div class="EXAMPLE">
                  <a name="AGRAM"></a>

                  <p><strong>Пример 33-13. Игры с
                  анаграммами</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# agram.sh: Игры с анаграммами.

# Поиск анаграмм...
LETTERSET=etaoinshrdlu

anagram "$LETTERSET" | # Найти все анаграммы в наборе символов...
grep '.......' |       # состоящие, как минимум из 7 символов,
grep '^is' |           # начинающиеся с 'is'
grep -v 's$' |         # исключая множественное число
grep -v 'ed$'          # и глаголы в прошедшем времени

#  Здесь используется утилита "anagram"
#+ которая входит в состав пакета "yawl" , разработанного автором.
#  http://ibiblio.org/pub/Linux/libs/yawl-0.2.tar.gz

exit 0                 # Конец.

bash$ sh agram.sh
islander
isolate
isolead
isotheral
</pre>
                </div>

                <p>См. также <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CONSTAT">Пример 27-2</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CRYPTOQUOTE">Пример 12-18</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SOUNDEX">Пример A-10</a>.</p>
              </li>

              <li>
                <p>Для создания блочных комментариев можно использовать
                <span class="QUOTE">"<a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ANONHEREDOC0">анонимные встроенные
                документы</a>"</span>. См. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COMMENTBLOCK">Пример 17-10</a>.</p>
              </li>

              <li>
                <p>Попытка вызова утилиты из сценария на машине, где
                эта утилита отсутствует, потенциально опасна. Для
                обхода подобных проблем можно воспользоваться утилитой
                <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WHATISREF">whatis</a>.</p>
<pre class="PROGRAMLISTING">CMD=command1                 # Основной вариант.
PlanB=command2               # Запасной вариант.

command_test=$(whatis "$CMD" | grep 'nothing appropriate')
#  Если 'command1' не найдена в системе, то 'whatis' вернет
#+ "command1: nothing appropriate."
#==&gt; От переводчика: Будьте внимательны! Если у вас локализованная версия whatis
#==&gt; то вывод от нее может отличаться от используемого здесь ('nothing appropriate')


if [[ -z "$command_test" ]]  # Проверка наличия утилиты в системе.
then
  $CMD option1 option2       #  Запуск команды с параметрами.
else                         #  Иначе,
  $PlanB                     #+ запустить command2 (запасной вариант).
fi
</pre>
                <br>
                <br>
              </li>

              <li>
                <p>Команда <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RUNPARTSREF">run-parts</a> удобна для запуска
                нескольких сценариев, особенно в комбинации с <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CRONREF">cron</a> или <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ATREF">at</a>.</p>
              </li>

              <li>
                <p>Было бы неплохо снабдить сценарий графическим
                интерфейстом X-Window. Для этого можно порекомендовать
                пакеты <span class="emphasis"><em class="EMPHASIS">Xscript</em></span>, <span class="emphasis"><em class="EMPHASIS">Xmenu</em></span> и <span class="emphasis"><em class="EMPHASIS">widtools</em></span>. Правда, первые
                два, кажется больше не поддерживаются разработчиками.
                Зато <span class="emphasis"><em class="EMPHASIS">widtools</em></span> можно получить
                <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html" "http:="" www.batse.msfc.nasa.gov="" ~mallozzi="" home="" software="" xforms="" src="" widtools-2.0.tgz"="" target="_top">здесь</a>.</p>

                <div class="CAUTION">
                  <table class="CAUTION" width="90%" border="0">
                    <tbody><tr>
                      <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/caution.gif" hspace="5" alt="Caution"></td>

                      <td align="left" valign="top">
                        <p>Пакет <span class="emphasis"><em class="EMPHASIS">widtools</em></span> (widget
                        tools) требует наличия библиотеки <span class="emphasis"><em class="EMPHASIS">XForms</em></span>. Кроме
                        того, необходимо слегка подправить <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MAKEFILEREF">Makefile</a>, чтобы этот
                        пакет можно было собрать на типичной
                        Linux-системе. Но хуже всего то, что три из
                        шести виджетов не работают :-(( (segfault).</p>
                      </td>
                    </tr>
                  </tbody></table>
                </div>

                <p>Для постороения приложений с графическим
                интерфейсом, можно попробовать <span class="emphasis"><em class="EMPHASIS">Tk</em></span>, или <span class="emphasis"><em class="EMPHASIS">wish</em></span> (надстройка над
                <span class="emphasis"><em class="EMPHASIS">Tcl</em></span>), <span class="emphasis"><em class="EMPHASIS">PerlTk</em></span> (Perl с поддержкой
                Tk), <span class="emphasis"><em class="EMPHASIS">tksh</em></span> (ksh с поддержкой
                Tk), <span class="emphasis"><em class="EMPHASIS">XForms4Perl</em></span> (Perl с
                поддержкой XForms), <span class="emphasis"><em class="EMPHASIS">Gtk-Perl</em></span> (Perl с
                поддержкой Gtk) или <span class="emphasis"><em class="EMPHASIS">PyQt</em></span> (Python с поддержкой
                Qt).</p>
              </li>
            </ul>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="SECURITYISSUES"></a>33.8. Проблемы безопасности</h2>

            <p>Уместным будет лишний раз предупредить о соблюдении мер
            предосторожности при работе с незнакомыми сценариями.
            Сценарий может содержать <span class="emphasis"><em class="EMPHASIS">червя</em></span>, <span class="emphasis"><em class="EMPHASIS">трояна</em></span> или даже <span class="emphasis"><em class="EMPHASIS">вирус</em></span>. Если вы получили
            сценарий не из источника, которому доверяете, то никогда не
            запускайте его с привилегиями root и не позволяйте
            вставлять его в список сценариев начальной инициализации
            системы в <code class="FILENAME">/etc/rc.d</code>, пока не убедитесь в том,
            что он безвреден для системы.</p>

            <p>Исследователи из Bell Labs и других организаций, включая
            M. Douglas McIlroy, Tom Duff, и Fred Cohen исследовали
            вопрос о возможности создания вирусов на языке сценариев
            командной оболочки, и пришли к выводу, что это делается
            очень легко и доступно даже для новичков. <a name="AEN13892" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN13892"><span class="footnote">[63]</span></a></p>

            <p>Это еще одна из причин, по которым следует изучать язык
            командной оболочки. Способность читать и понимать сценарии
            поможет вам предотвратить возможность взлома и/или
            разрушения вашей системы.</p>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="PORTABILITYISSUES"></a>33.9. Проблемы
            переносимости</h2>

            <p>Эта книга делает упор на создании сценариев для
            командной оболочки Bash, для операционной системы
            GNU/Linux. Тем не менее, многие рекомендации, приводимые
            здесь, могут быть вполне применимы и для других командных
            оболочек, таких как <strong class="COMMAND">sh</strong> и <strong class="COMMAND">ksh</strong>.</p>

            <p>Многие версии командных оболочек стремятся следовать
            стандарту POSIX 1003.2. Вызывая Bash с ключом <code class="OPTION">--posix</code>, или вставляя <strong class="COMMAND">set -o posix</strong> в начало сценария,
            вы можете заставить Bash очень близко следовать этому
            стандарту. Но, даже без этого ключа, большинство сценариев,
            написанных для Bash, будут работать под управлением <strong class="COMMAND">ksh</strong>, и наоборот, т.к. Chet Ramey
            перенес многие особенности, присущие <strong class="COMMAND">ksh</strong>, в последние версии Bash.</p>

            <p>В коммерческих версиях UNIX, сценарии, использующие
            GNU-версии стандартных утилит и команд, могут оказаться
            неработоспособными. Однако, с течением времени, таких
            проблем остается все меньше и меньше, поскольку утилиты
            GNU, в большинстве своем, заместили свои проприетарные
            аналоги в UNIX. После того, как <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html" "http:="" linux.oreillynet.com="" pub="" a="" linux="" 2002="" 02="" 28="" caldera.html"="" target="_top">Caldera дала разрешение на публикацию
            исходного кода</a> некоторых версий оригинальных утилит
            UNIX, этот процесс значительно ускорился.</p>

            <p>Bash имеет некоторые особенности, недоступные в
            традиционном Bourne shell. Среди них:</p>

            <ul>
              <li>
                <p>Некоторые дополнительные <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#INVOCATIONOPTIONSREF">ключи вызова</a></p>
              </li>

              <li>
                <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COMMANDSUBREF">Подстановка команд</a>, с
                использованием нотации <strong class="COMMAND">$( )</strong></p>
              </li>

              <li>
                <p>Некоторые <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#STRINGMANIP">операции над строками</a></p>
              </li>

              <li>
                <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PROCESSSUBREF">Подстановка процессов</a></p>
              </li>

              <li>
                <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BUILTINREF">встроенные команды</a> Bash</p>
              </li>
            </ul>
            <br>
            <br>

            <p>Более подробный список характерных особенностей Bash, вы
            найдете в <a href="ftp://ftp.cwru.edu/pub/bash/FAQ" target="_top">Bash F.A.Q.</a>.</p>
          </div>

          <div class="SECT1">
            <hr>

            <h2 class="SECT1"><a name="WINSCRIPT"></a>33.10. Сценарии командной оболочки
            под Windows</h2>

            <p>Даже те пользователи, которые работают в <span class="emphasis"><em class="EMPHASIS">другой</em></span>, не UNIX-подобной
            операционной системе, смогут запускать сценарии командной
            оболочки, а потому -- найти для себя много полезного в этой
            книге. Пакеты <!--noindex--><a href="http://sourceware.cygnus.com/cygwin/" target="_top">Cygwin</a><!--/noindex--> от Cygnus, и <!--noindex--><a href="http://www.mkssoftware.com/" target="_top">MKS utilities</a><!--/noindex--> от Mortice Kern
            Associates, позволяют дополнить Windows возможностями
            командной оболочки.</p>
          </div>
        </div>

        <div class="CHAPTER">
          <hr>

          <h1><a name="BASH2"></a>Глава 34. Bash, версия 2</h1>

          <p><a name="BASH2REF"></a></p>

          <p>Текущая версия <span class="emphasis"><em class="EMPHASIS">Bash</em></span>, та, которая скорее всего
          установлена в вашей системе, фактически -- 2.XX.Y.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo $BASH_VERSION</strong></code>
<code class="COMPUTEROUTPUT">2.05.8(1)-release</code>
             
</pre>
          В этой версии классического языка сценариев Bash были
          добавлены переменные-массивы, <a name="AEN13946" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN13946"><span class="footnote">[64]</span></a> расширение строк и
          подстановка параметров, улучшен метод косвенных ссылок на
          переменные.<br>
          <br>

          <div class="EXAMPLE">
            <a name="EX77"></a>

            <p><strong>Пример 34-1. Расширение строк</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# "Расширение" строк (String expansion).
# Введено в Bash, начиная с версии 2.

# Строки вида  $'xxx'
# могут содержать дополнительные экранированные символы.

echo $'Звонок звенит 3 раза \a \a \a'
echo $'Три перевода формата \f \f \f'
echo $'10 новых строк \n\n\n\n\n\n\n\n\n\n'

exit 0
</pre>
          </div>

          <p><a name="VARREFNEW"></a></p>

          <div class="EXAMPLE">
            <a name="EX78"></a>

            <p><strong>Пример 34-2. Косвенные ссылки на переменные --
            новый метод</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# Косвенные ссылки на переменные.


a=letter_of_alphabet
letter_of_alphabet=z

echo "a = $a"           # Прямая ссылка.

echo "Now a = ${!a}"    # Косвенная ссылка.
# Форма записи ${!variable} намного удобнее старой "eval var1=\$$var2"

echo

t=table_cell_3
table_cell_3=24
echo "t = ${!t}"        # t = 24
table_cell_3=387
echo "Значение переменной t изменилось на ${!t}"    # 387

# Теперь их можно использовать для ссылок на элементы массива,
# или для эмуляции многомерных массивов.
# Было бы здорово, если бы косвенные ссылки допускали индексацию.

exit 0
</pre>
          </div>

          <div class="EXAMPLE">
            <a name="RESISTOR"></a>

            <p><strong>Пример 34-3. Простая база данных, с применением
            косвенных ссылок</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# resistor-inventory.sh
# Простая база данных, с применением косвенных ссылок.

# ============================================================== #
# Данные

B1723_value=470                                   # сопротивление (Ом)
B1723_powerdissip=.25                             # рассеиваемая мощность (Вт)
B1723_colorcode="желтый-фиолетовый-коричневый"    # цветовая маркировка
B1723_loc=173                                     # где
B1723_inventory=78                                # количество (шт)

B1724_value=1000
B1724_powerdissip=.25
B1724_colorcode="коричневый-черный-красный"
B1724_loc=24N
B1724_inventory=243

B1725_value=10000
B1725_powerdissip=.25
B1725_colorcode="коричневый-черный-оранжевый"
B1725_loc=24N
B1725_inventory=89

# ============================================================== #


echo

PS3='Введите ноиер: '

echo

select catalog_number in "B1723" "B1724" "B1725"
do
  Inv=${catalog_number}_inventory
  Val=${catalog_number}_value
  Pdissip=${catalog_number}_powerdissip
  Loc=${catalog_number}_loc
  Ccode=${catalog_number}_colorcode

  echo
  echo "Номер по каталогу $catalog_number:"
  echo "Имеется в наличии ${!Inv} шт. [${!Val} Ом / ${!Pdissip} Вт]."
  echo "Находятся в лотке # ${!Loc}."
  echo "Цветовая маркировка: \"${!Ccode}\"."

  break
done

echo; echo

# Упражнение:
# ----------
# Переделайте этот сценарий так, чтобы он использовал массивы вместо косвенных ссылок.
# Какой из вариантов более простой и интуитивный?


# Примечание:
# ----------
#  Язык командной оболочки не очень удобен для написания приложений,
#+ работающих с базами данных.
#  Для этой цели лучше использовать языки программирования, имеющие
#+ развитые средства для работы со структурами данных,
#+ такие как C++ или Java (может быть Perl).

exit 0
</pre>
          </div>

          <div class="EXAMPLE">
            <a name="EX79"></a>

            <p><strong>Пример 34-4. Массивы и другие хитрости для
            раздачи колоды карт в четыре руки</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# На старых системах может потребоваться вставить #!/bin/bash2.

# Карты:
# раздача в четыре руки.

UNPICKED=0
PICKED=1

DUPE_CARD=99

LOWER_LIMIT=0
UPPER_LIMIT=51
CARDS_IN_SUIT=13
CARDS=52

declare -a Deck
declare -a Suits
declare -a Cards
# Проще и понятнее было бы, имей мы дело
# с одним 3-мерным массивом.
# Будем надеяться, что в будущем, поддержка многомерных массивов будет введена в Bash.


initialize_Deck ()
{
i=$LOWER_LIMIT
until [ "$i" -gt $UPPER_LIMIT ]
do
  Deck[i]=$UNPICKED   # Пометить все карты в колоде "Deck", как "невыданная".
  let "i += 1"
done
echo
}

initialize_Suits ()
{
Suits[0]=Т # Трефы
Suits[1]=Б # Бубны
Suits[2]=Ч # Червы
Suits[3]=П # Пики
}

initialize_Cards ()
{
Cards=(2 3 4 5 6 7 8 9 10 В Д K Т)
# Альтернативный способ инициализации массива.
}

pick_a_card ()
{
card_number=$RANDOM
let "card_number %= $CARDS"
if [ "${Deck[card_number]}" -eq $UNPICKED ]
then
  Deck[card_number]=$PICKED
  return $card_number
else
  return $DUPE_CARD
fi
}

parse_card ()
{
number=$1
let "suit_number = number / CARDS_IN_SUIT"
suit=${Suits[suit_number]}
echo -n "$suit-"
let "card_no = number % CARDS_IN_SUIT"
Card=${Cards[card_no]}
printf %-4s $Card
# Вывод по столбцам.
}

seed_random ()  # Переустановка генератора случайных чисел.
{
seed=`eval date +%s`
let "seed %= 32766"
RANDOM=$seed
}

deal_cards ()
{
echo

cards_picked=0
while [ "$cards_picked" -le $UPPER_LIMIT ]
do
  pick_a_card
  t=$?

  if [ "$t" -ne $DUPE_CARD ]
  then
    parse_card $t

    u=$cards_picked+1
    # Возврат к индексации с 1 (временно).
    let "u %= $CARDS_IN_SUIT"
    if [ "$u" -eq 0 ]   # вложенный if/then.
    then
     echo
     echo
    fi
    # Смена руки.

    let "cards_picked += 1"
  fi
done

echo

return 0
}


# Структурное программирование:
# вся логика приложения построена на вызове функций.

#================
seed_random
initialize_Deck
initialize_Suits
initialize_Cards
deal_cards

exit 0
#================



# Упражнение 1:
# Добавьте комментарии, чтобы до конца задокументировать этот сценарий.

# Упражнение 2:
# Исправьте сценарий так, чтобы карты в каждой руке выводились отсортированными по масти.
# Вы можете добавить и другие улучшения.

# Упражнение 3:
# Упростите логику сценария.
</pre>
          </div>
        </div>
      </div>

      <div class="CHAPTER">
        <hr>

        <h1><a name="ENDNOTES"></a>Глава 35. Замечания и дополнения</h1>

        <div class="SECT1">
          <h2 class="SECT1"><a name="AUTHORSNOTE"></a>35.1. От автора</h2>

          <p>Как я пришел к мысли о написании этой книги? Это необычная
          история. Случилось это лет несколько тому назад. Мне
          потребовалось изучить язык командной оболочки -- а что может
          быть лучше, как не чтение хорошей книги!? Я надеялся купить
          учебник и справочник, которые охватывали бы в полной мере
          данную тематику. Я искал книгу, которая возьмет трудные
          понятия, вывернет их наизнанку и подробно разжует на хорошо
          откомментированных примерах. В общем, я искал очень хорошую
          книгу. К сожалению, в природе таковой не существовало,
          поэтому я счел необходимым написать ее.</p>

          <p>Это напоминает мне сказку о сумасшедшем профессоре.
          Помешанный, до безумия, при виде книги, любой книги -- в
          библиотеке, в книжном магазине -- не важно где, им овладевала
          уверенность в том, что и он мог бы написать эту книгу, причем
          сделать это гораздо лучше. Он стремительно мчался домой и
          садился за создание своей собственной книги с тем же
          названием. Когда он умер, в его доме нашли несколько тысяч,
          написанных им книг, этого количества хватило бы, чтобы
          посрамить самого Айзека Азимова. Книги, может быть и не были
          так хороши -- кто знает, но разве это имеет какое-то
          значение? Вот -- человек, жил своими грезами, пусть одержимый
          и движимый ими, но я не могу удержаться от восхищения старым
          чудаком...</p>
        </div>

        <div class="SECT1">
          <hr>

          <h2 class="SECT1"><a name="ABOUTAUTHOR"></a>35.2. Об авторе</h2>

          <p>Автор не стремится ни к званиям, ни к наградам, им движет
          неодолимое желание писать. <a name="AEN13971" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN13971"><span class="footnote">[65]</span></a> Эта книга -- своего рода
          отдых от основной работы, <!--noindex--><a href="http://personal.riverusers.com/~thegrendel/hmw50.zip" target="_top">HOW-2 Meet Women: The Shy Man's Guide to
          Relationships</a><!--/noindex--> (Руководство Застенчивого Мужчины о том Как
          Познакомиться С Женщиной) . Он также написал <!--noindex--><a href="http://tldp.org/HOWTO/Software-Building-HOWTO.html" target="_top">Software-Building HOWTO</a><!--/noindex-->.</p>

          <p>Пользуется Linux с 1995 года (Slackware 2.2, kernel
          1.2.1). Выпустил несколько программ, среди которых <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html" "http:="" ibiblio.org="" pub="" linux="" utils="" file="" cruft-0.2.tar.gz"="" target="_top">cruft</a> -- утилита шифрования, заменявшая
          стандартную UNIX-овую crypt, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html" "http:="" ibiblio.org="" pub="" linux="" apps="" financial="" mcalc-1.6.tar.gz"="" target="_top">mcalc</a> -- финансовый калькулятор, для
          выполнения расчетов по займам, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html" "http:="" ibiblio.org="" pub="" linux="" games="" amusements="" judge-1.0.tar.gz"="" target="_top">judge</a> и <!--noindex--><a href="http://ibiblio.org/pub/Linux/libs/yawl-0.2.tar.gz" target="_top">yawl</a><!--/noindex--> -- пакет игр со словами.
          Программировать начинал с языка FORTRAN IV на CDC 3800, но не
          испытывает ностальгии по тем дням.</p>

          <p>Живет в глухой, заброшенной деревушке со своей женой и
          собакой.</p>
        </div>

        <div class="SECT1">
          <hr>

          <h2 class="SECT1"><a name="TOOLSUSED"></a>35.3. Инструменты, использовавшиеся при
          создании книги</h2>

          <div class="SECT2">
            <h3 class="SECT2"><a name="SOFTWARE-HARDWARE"></a>35.3.1. Аппаратура</h3>

            <p>IBM Thinkpad, model 760XL laptop (P166, 104 Mb RAM) под
            управлением Red Hat 7.1/7.3. Несомненно, это довольно
            медлительный агрегат, но он имеет отличную клавиатуру, и
            это много лучше, чем пара карандашей и письменный стол.</p>
          </div>

          <div class="SECT2">
            <hr>

            <h3 class="SECT2"><a name="SOFTWARE-PRINTWARE"></a>35.3.2. Программное
            обеспечение</h3>

            <ol type="i">
              <li>
                <p>Мощный текстовый редактор <!--noindex--><a href="http://www.vim.org/" target="_top">vim</a><!--/noindex--> (автор: Bram Moolenaar) .</p>
              </li>

              <li>
                <p><!--noindex--><a href="http://www.netfolder.com/DSSSL/" target="_top">OpenJade</a><!--/noindex--> -- инструмент, выполняющий,
                на основе DSSSL, верификацию и преобразование
                SGML-документов в другие форматы.</p>
              </li>

              <li>
                <p><!--noindex--><a href="http://nwalsh.com/docbook/dsssl/" target="_top">Таблицы стилей DSSSL от Norman
                Walsh</a><!--/noindex-->.</p>
              </li>

              <li>
                <p><span class="emphasis"><em class="EMPHASIS">DocBook, The Definitive
                Guide</em></span> (Norman Walsh, Leonard Muellner
                O'Reilly, ISBN 1-56592-580-7). Полное руководство
                по созданию документов в формате Docbook SGML.</p>
              </li>
            </ol>
          </div>
        </div>

        <div class="SECT1">
          <hr>

          <h2 class="SECT1 cc_cursor"><a name="CREDITS"></a>35.4. Благодарности</h2>

          <p>Без участия сообщества этот проект был бы невозможен.
          Автор признает, что без посторонней помощи, написание этой
          книги стало бы невыполнимой задачей и благодарит всех, кто
          оказал посильную помощь.</p>

          <p><a href="mailto:feloy@free.fr" target="_top">Philippe Martin</a> -- перевел этот документ в
          формат DocBook/SGML. Работает в маленькой французской
          компании, в качестве разработчика программного обеспечения. В
          свободное от работы время -- любит работать над документацией
          или программным обеспечением для GNU/Linux, читать книги,
          слушать музыку и веселиться с друзьями. Вы можете столкнуться
          с ним, где-нибудь во Франции, в провинции Басков, или
          написать ему письмо на <a href="mailto:feloy@free.fr" target="_top">feloy@free.fr</a>.</p>

          <p>Philippe Martin также отметил, что возможно использование
          позиционных параметров за $9, при использовании {фигурных
          скобок}, см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX17">Пример 4-5</a>.</p>

          <p><a href="mailto:stephane_chazelas@yahoo.fr" target="_top">Stephane Chazelas</a> -- выполнил титаническую
          работу по корректировке, дополнению и написанию примеров
          сценариев. Фактически, он взвалил на свои плечи обязанности
          <strong class="COMMAND">редактора</strong> этого документа. Огромное
          спасибо!</p>

          <p>Особенно я хотел бы поблагодарить <span class="emphasis"><em class="EMPHASIS">Patrick Callahan</em></span>, <span class="emphasis"><em class="EMPHASIS">Mike Novak</em></span> и <span class="emphasis"><em class="EMPHASIS">Pal Domokos</em></span> за исправление
          ошибок и неточностей, за разъяснения и дополнения. Их живое
          обсуждение проблем, связанных с созданием сценариев на языке
          командной оболочки вдохновило меня на попытку сделать этот
          документ более удобочитаемым.</p>

          <p>Я благодарен Jim Van Zandt за выявленные им ошибки и
          упущения, в версии 0.2 этого документа, и за поучительный
          пример сценария.</p>

          <p>Большое спасибо <a href="mailto:mikaku@fiwix.org" target="_top">Jordi Sanfeliu</a> за то, что он дал
          возможность использовать его прекрасный сценарий в этой книге
          (<a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TREE">Пример A-19</a>).</p>

          <p>Выражаю свою благодарность <a href="mailto:charpov@cs.unh.edu" target="_top">Michel Charpentier</a> за разрешение
          использовать его <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DCREF">dc</a> сценарий разложения на простые
          множители (<a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FACTR">Пример 12-37</a>).</p>

          <p>Спасибо <a href="mailto:friedman@prep.ai.mit.edu" target="_top">Noah Friedman</a>, предоставившему право
          использовать его сценарий (<a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#STRING">Пример A-20</a>).</p>

          <p><a href="mailto:emmanuel.rouat@wanadoo.fr" target="_top">Emmanuel Rouat</a> предложил несколько
          изменений и дополнений в разделах, посвященных <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COMMANDSUBREF">подстановке команд</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ALIASREF">псевдонимам</a>. Он так же предоставил
          замечательный пример файла <code class="FILENAME">.bashrc</code> (<a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SAMPLE-BASHRC">Приложение G</a>).</p>

          <p><a href="mailto:heiner.steven@odn.de" target="_top">Heiner Steven</a> любезно разрешил
          опубликовать его сценарий <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BASE">Пример 12-33</a>. Он сделал множество
          исправлений и внес большое количество предложений. Особое
          спасибо!</p>

          <p>Rick Boivie предоставил отличный сценарий, демонстрирующий
          рекурсию, <span class="emphasis"><em class="EMPHASIS">pb.sh</em></span> (<a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PBOOK">Пример 33-7</a>) и внес предложения по
          повышению производительности сценария <span class="emphasis"><em class="EMPHASIS">monthlypmt.sh</em></span> (<a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MONTHLYPMT">Пример 12-32</a>).</p>

          <p>Florian Wisser оказывал содействие при написании разделов,
          посвященных строкам (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#STRTEST">Пример 7-6</a>).</p>

          <p>Oleg Philon передал свои предложения относительно команд
          <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CUTREF">cut</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PIDOFREF">pidof</a>.</p>

          <p>Michael Zick расширил пример с <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EMPTYARRAY">пустыми массивами</a>, введя туда
          демонстрацию необычных свойств массивов. Он также предоставил
          ряд других примеров.</p>

          <p>Marc-Jano Knopp выполнил исправления в разделе,
          посвященном пакетным файлам DOS.</p>

          <p>Hyun Jin Cha, в процессе работы над корейским переводом,
          обнаружил несколько опечаток в документе. Спасибо ему за
          это!</p>

          <p>Andreas Abraham передал большое число типографских ошибок
          и внес ряд исправлений. Особое спасибо!</p>

          <p>Кроме того, я хотел бы выразить свою признательность Gabor
          Kiss, Leopold Toetsch, Peter Tillier, Marcus Berglof, Tony
          Richardson, Nick Drage, Rich Bartell, Jess Thrysoee, Adam
          Lazur, Bram Moolenaar, Baris Cicek, Greg Keraunen, Keith
          Matthews, Sandro Magi, Albert Reiner, Dim Segebart, Rory
          Winston, Lee Bigelow, Wayne Pollock, <span class="QUOTE">"jipe"</span>, Emilio Conti, Dennis
          Leeuw, Dan Jacobson и David Lawyer (автор 4-х HOWTO).</p>

          <p>Мои благодарности <a href="mailto:chet@po.cwru.edu" target="_top">Chet Ramey</a> и Brian Fox за создание <strong class="COMMAND">Bash</strong> -- этого элегантного и мощного
          инструмента!</p>

          <p>Особое спасибо добровольцам из <!--noindex--><a href="http://www.tldp.org/" target="_top">Linux Documentation Project</a><!--/noindex-->. Проект LDP
          сделал возможным публикацию этой книги в своем архиве.</p>

          <p>Больше всего я хотел бы выразить свою благодарность моей
          супруге, Anita, за ее эмоциональную поддержку.</p>
        </div>
      </div>
      <hr>

      <h1><a name="BIBLIO"></a>Литература</h1>
      <a name="BIBLIOREF"></a>

      <div class="BIBLIOENTRY">
        <a name="AEN14061"></a>

        <p><span class="EDITOR">Edited by Peter Denning</span>, <em>Computers
        Under Attack: Intruders, Worms, and Viruses</em>, ACM Press,
        1990, 0-201-53067-8.</p>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Содержит несколько статей о вирусах, написаных на языке
            командной оболочки.</p>

            <p>*</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14075"></a>

        <p><span class="AUTHOR">Dale Dougherty</span> <span class="AUTHOR">and Arnold Robbins</span>, <em>Sed and
        Awk</em>, 2nd edition, O'Reilly and Associates, 1997,
        1-156592-225-5.</p>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Чтобы раскрыть всю мощь командной оболочки, вам
            наверняка потребуется знакомство с <strong class="COMMAND">sed</strong> и <strong class="COMMAND">awk</strong>. Это обычный учебник. Здесь
            вы найдете превосходное введение в <span class="QUOTE">"регулярные выражения"</span>.
            Обязательно прочитайте эту книгу.</p>

            <p>*</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14096"></a>

        <p><span class="AUTHOR">Aeleen Frisch</span>, <em>Essential System
        Administration</em>, 3rd edition, O'Reilly and Associates,
        2002, 0-596-00343-9.</p>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Это замечательное руководство для системных
            администраторов. Может служить неплохим введением в
            программирование сценариев. Содержит подробные пояснения к
            сценариям загрузки и инициализации системы.</p>

            <p>*</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14111"></a>

        <p><span class="AUTHOR">Stephen Kochan</span> <span class="AUTHOR">and Patrick Woods</span>, <em>Unix Shell
        Programming</em>, Hayden, 1990, 067248448X.</p>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Стандартный справочник, хотя немного устаревший.</p>

            <p>*</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14128"></a>

        <p><span class="AUTHOR">Neil Matthew</span> <span class="AUTHOR">and Richard Stones</span>, <em>Beginning Linux
        Programming</em>, Wrox Press, 1996, 1874416680.</p>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Дает хороший, глубокий охват различных языков
            программирования, доступных в Linux, включая довольно
            сильную главу по программированию в командной оболочке.</p>

            <p>*</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="MAYERREF"></a>

        <p><span class="AUTHOR">Herbert Mayer</span>, <em>Advanced C
        Programming on the IBM PC</em>, Windcrest Books, 1989,
        0830693637.</p>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Замечательная книга по алгоритмам и практическому
            программированию.</p>

            <p>*</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14159"></a>

        <p><span class="AUTHOR">David Medinets</span>, <em>Unix Shell
        Programming Tools</em>, McGraw-Hill, 1999, 0070397333.</p>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Отличная книга по программированию в командной оболочке,
            с примерами, и кратким введением в Tcl и Perl.</p>

            <p>*</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14173"></a>

        <p><span class="AUTHOR">Cameron Newham</span> <span class="AUTHOR">and Bill Rosenblatt</span>, <em>Learning the
        Bash Shell</em>, 2nd edition, O'Reilly and Associates,
        1998, 1-56592-347-2.</p>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Это отважная попытка создать учебник для начинающих, но
            он получился несколько несовершенным, к тому же не
            изобилует примерами сценариев.</p>

            <p>*</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14191"></a>

        <p><span class="AUTHOR">Anatole Olczak</span>, <em>Bourne Shell Quick
        Reference Guide</em>, ASP, Inc., 1991, 093573922X.</p>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Очень удобный карманный справочник, несмотря на
            недостатки, при охвате специфичных свойств Bash.</p>

            <p>*</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14205"></a>

        <p><span class="AUTHOR">Jerry Peek,</span> <span class="AUTHOR">Tim O'Reilly,</span> <span class="AUTHOR">and Mike Loukides</span>, <em>Unix Power
        Tools</em>, 2nd edition, O'Reilly and Associates, Random
        House, 1997, 1-56592-260-3.</p>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Содержит ряд очень информативных разделов, посвященных
            программированию в командной оболочке, но не может
            рассматриваться как учебное пособие.</p>

            <p>*</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14228"></a>

        <p><span class="AUTHOR">Clifford Pickover</span>, <em>Computers,
        Pattern, Chaos, and Beauty</em>, St. Martin's Press, 1990,
        0-312-04123-3.</p>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Сокровищница идей и рецептов по машинным
            вычислениям.</p>

            <p>*</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14242"></a>

        <p><span class="AUTHOR">George Polya</span>, <em>How To Solve It</em>,
        Princeton University Press, 1973, 0-691-02356-5.</p>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Классический учебник по методам решения задач.</p>

            <p>*</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14256"></a>

        <p><span class="AUTHOR">Arnold Robbins</span>, <em>Bash Reference
        Card</em>, SSC, 1998, 1-58731-010-5.</p>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Замечательный карманный справочник по Bash. Стоит всего
            $4.95, но также доступен для свободного скачивания <!--noindex--><a href="http://www.ssc.com/ssc/bash/" target="_top">on-line</a><!--/noindex--> в формате PDF.</p>

            <p>*</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14271"></a>

        <p><span class="AUTHOR">Arnold Robbins</span>, <em>Effective Awk
        Programming</em>, Free Software Foundation / O'Reilly and
        Associates, 2000, 1-882114-26-4.</p>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Самое лучшее учебное руководство и справочник по <strong class="COMMAND">awk</strong>. Свободная электронная версия
            книги включена в состав документации к <strong class="COMMAND">awk</strong>. Печатное издание последней
            версии доступно на сайте O'Reilly and Associates.</p>

            <p>Эта книга служила источником вдохновения для автора этой
            книги.</p>

            <p>*</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14288"></a>

        <p><span class="AUTHOR">Bill Rosenblatt</span>, <em>Learning the Korn
        Shell</em>, O'Reilly and Associates, 1993,
        1-56592-054-6.</p>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Эта, хорошо написанная книга, содержит массу указаний по
            созданию сценариев командной оболочки.</p>

            <p>*</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14302"></a>

        <p><span class="AUTHOR">Paul Sheer</span>, <em>LINUX: Rute User's
        Tutorial and Exposition</em>, 1st edition, , 2002,
        0-13-033351-4.</p>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Очень хорошее введение в системное администрирование
            Linux.</p>

            <p>Эта книга доступна в <!--noindex--><a href="http://rute.sourceforge.net/" target="_top">on-line</a><!--/noindex-->.</p>

            <p>*</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14319"></a>

        <p><span class="AUTHOR">Ellen Siever</span> <span class="AUTHOR">and the staff of O'Reilly and
        Associates</span>, <em>Linux in a Nutshell</em>, 2nd edition,
        O'Reilly and Associates, 1999, 1-56592-585-8.</p>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Один из лучших справочников по командам Linux, имеет
            раздел, посвященный Bash.</p>

            <p>*</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14336"></a>

        <p><em>The UNIX CD Bookshelf</em>, 3rd edition, O'Reilly
        and Associates, 2003, 0-596-00392-7.</p>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Сборник из 7-ми книг по UNIX на CD ROM. В состав
            сборника входят такие книги, как <span class="emphasis"><em class="EMPHASIS">UNIX Power Tools</em></span>, <span class="emphasis"><em class="EMPHASIS">Sed and Awk</em></span> и <span class="emphasis"><em class="EMPHASIS">Learning the Korn Shell</em></span>.
            Полный набор необходимых справочных и учебных материалов,
            который вам только может понадобиться. Стоит примерно
            $130.</p>

            <p>*</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14350"></a>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Книги издательства O'Reilly, посвященные Perl.</p>

            <p>---</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14354"></a>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Ben Okopnik опубликовал серию отличных статей <span class="emphasis"><em class="EMPHASIS">introductory Bash scripting</em></span> в
            выпусках 53, 54, 55, 57 и 59 на сайте <!--noindex--><a href="http://www.linuxgazette.com/" target="_top">Linux Gazette</a><!--/noindex--> , и статью <span class="QUOTE">"The Deep, Dark Secrets of
            Bash"</span> в выпуске 56.</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14360"></a>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Chet Ramey <span class="emphasis"><em class="EMPHASIS">bash - The GNU Shell</em></span> -- серия
            статей в 3 и 4 выпусках <!--noindex--><a href="http://www.linuxjournal.com/" target="_top">Linux Journal</a><!--/noindex-->, Июль-Август 1994.</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14365"></a>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Mike G <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html" "http:="" www.tldp.org="" howto="" bash-prog-intro-howto.html"="" target="_top">Bash-Programming-Intro HOWTO</a>.</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14369"></a>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Richard <!--noindex--><a href="http://www.injunea.demon.co.uk/index.htm" target="_top">UNIX Scripting Universe</a><!--/noindex-->.</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14373"></a>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Chet Ramey <a href="ftp://ftp.cwru.edu/pub/bash/FAQ" target="_top">Bash F.A.Q.</a></p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14377"></a>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Ed Schaefer <!--noindex--><a href="http://www.unixreview.com/columns/schaefer/" target="_top">Shell Corner</a><!--/noindex--> на <!--noindex--><a href="http://www.unixreview.com/" target="_top">Unix Review</a><!--/noindex-->.</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14382"></a>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Примеры сценариев: <!--noindex--><a href="http://alge.anart.no/linux/scripts/" target="_top">Lucc's Shell Scripts</a><!--/noindex--> .</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14386"></a>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Примеры сценариев: <!--noindex--><a href="http://www.shelldorado.com/" target="_top">SHELLdorado</a><!--/noindex--> .</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14390"></a>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Примеры сценариев: <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html" "http:="" clri6f.gsi.de="" gnu="" bash-2.01="" examples="" scripts.noah="" "="" target="_top">Noah Friedman's script site</a>.</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14394"></a>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Steve Parker <!--noindex--><a href="http://steve-parker.org/sh/sh.shtml" target="_top">Shell Programming Stuff</a><!--/noindex-->.</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14398"></a>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Примеры сценариев: <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html" "http:="" sourceforge.net="" snippet="" browse.php?by="lang&amp;lang=7&quot;" target="_top">SourceForge Snippet Library - shell
            scripts</a>.</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14402"></a>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Giles Orr <!--noindex--><a href="http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/" target="_top">Bash-Prompt HOWTO</a><!--/noindex-->.</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14406"></a>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Замечательное руководство по регулярным выражениям,
            <strong class="COMMAND">sed</strong> и <strong class="COMMAND">awk</strong> <!--noindex--><a href="http://www.grymoire.com/Unix/index.html" target="_top">The UNIX Grymoire</a><!--/noindex-->.</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14412"></a>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Eric Pement <!--noindex--><a href="http://www.student.northpark.edu/pemente/sed/" target="_top">sed resources page</a><!--/noindex-->.</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14416"></a>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html" "http:="" sunsite.ualberta.ca="" documentation="" gnu="" gawk-3.0.6="" gawk.html"="" target="_top">The GNU <strong class="COMMAND">gawk</strong> reference manual</a>
            (<strong class="COMMAND">gawk</strong> -- GNU-версия <strong class="COMMAND">awk</strong> для ОС Linux и BSD).</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14423"></a>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Trent Fisher <!--noindex--><a href="http://www.cs.pdx.edu/~trent/gnu/groff/groff.html" target="_top">groff tutorial</a><!--/noindex-->.</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14427"></a>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Mark Komarinski <!--noindex--><a href="http://www.tldp.org/HOWTO/Printing-Usage-HOWTO.html" target="_top">Printing-Usage HOWTO</a><!--/noindex-->.</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14431"></a>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Хороший материал по <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IOREDIRREF">перенаправлению ввода/вывода</a> <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html" "http:="" sunsite.ualberta.ca="" documentation="" gnu="" textutils-2.0="" html_chapter="" textutils_10.html"="" target="_top">глава 10</a> на сайте <!--noindex--><a href="http://sunsite.ualberta.ca/Documentation" target="_top">University of Alberta</a><!--/noindex-->.</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14437"></a>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p><a href="mailto:humbubba@smarty.smart.net" target="_top">Rick Hohensee</a> <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html" "ftp:="" ftp.gwdg.de="" pub="" linux="" install="" clienux="" interim="" osimpa.tgz"="" target="_top">osimpa</a> -- ассемблер для процессора i386,
            написан полностью на Bash.</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14442"></a>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Rocky Bernstein ведет разработку <span class="QUOTE">"полнофункционального"</span> <!--noindex--><a href="http://bashdb.sourceforge.net/" target="_top">отладчика</a><!--/noindex--> для Bash.</p>

            <p>---</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14448"></a>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Отличное руководство "Bash Reference Manual",
            авторы Chet Ramey и Brian Fox, распространяется в составе
            пакета "bash-2-doc" (доступен как rpm). В этом
            пакете вы найдете особенно поучительные примеры.</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14451"></a>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Группа новостей <a href="news:comp.unix.shell" target="_top">comp.os.unix.shell</a>.</p>
          </div>
        </div>
      </div>

      <div class="BIBLIOENTRY">
        <a name="AEN14455"></a>

        <div class="BIBLIOENTRYBLOCK" style="margin-left: 0.5in">
          <div class="ABSTRACT">
            <p>Страницы руководства man по <strong class="COMMAND">bash</strong> и <strong class="COMMAND">bash2</strong>, <strong class="COMMAND">date</strong>, <strong class="COMMAND">expect</strong>, <strong class="COMMAND">expr</strong>, <strong class="COMMAND">find</strong>, <strong class="COMMAND">grep</strong>, <strong class="COMMAND">gzip</strong>, <strong class="COMMAND">ln</strong>, <strong class="COMMAND">patch</strong>, <strong class="COMMAND">tar</strong>, <strong class="COMMAND">tr</strong>, <strong class="COMMAND">bc</strong>, <strong class="COMMAND">xargs</strong>. Странички info по <strong class="COMMAND">bash</strong>, <strong class="COMMAND">dd</strong>, <strong class="COMMAND">m4</strong>, <strong class="COMMAND">gawk</strong> и <strong class="COMMAND">sed</strong>.</p>
          </div>
        </div>
      </div>

      <div class="APPENDIX">
        <hr>

        <h1><a name="CONTRIBUTED-SCRIPTS"></a>Приложение A. Дополнительные
        примеры сценариев</h1>

        <p>В этом приложении собраны сценарии, которые не попали в
        основной текст документа. Однако, они определенно стоят того,
        что бы вы потратили время на их изучение.</p>

        <div class="EXAMPLE">
          <a name="MANVIEW"></a>

          <p><strong>Пример A-1. manview: Просмотр страниц руководств
          man</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# manview.sh: Просмотр страниц руководств man в форматированном виде.

#  Полезен писателям страниц руководств, позволяет просмотреть страницы в исходном коде
#+ как они будут выглядеть в конечном виде.

E_WRONGARGS=65

if [ -z "$1" ]
then
  echo "Порядок использования: `basename $0` имя_файла"
  exit $E_WRONGARGS
fi

groff -Tascii -man $1 | less

# Если страница руководства включает в себя таблицы и/или выражения,
# то этот сценарий "стошнит".
# Для таких случаев можно использовать следующую строку.
#
#   gtbl &lt; "$1" | geqn -Tlatin1 | groff -Tlatin1 -mtty-char -man
#
#   Спасибо S.C.

exit 0
</pre>
        </div>

        <div class="EXAMPLE">
          <a name="MAILFORMAT"></a>

          <p><strong>Пример A-2. mailformat: Форматирование электронных
          писем</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# mail-format.sh: Форматирование электронных писем.

# Удаляет символы "^", табуляции и ограничивает чрезмерно длинные строки.

# =================================================================
#                 Стандартная проверка аргументов
ARGS=1
E_BADARGS=65
E_NOFILE=66

if [ $# -ne $ARGS ]  # Проверка числа аргументов
then
  echo "Порядок использования: `basename $0` имя_файла"
  exit $E_BADARGS
fi

if [ -f "$1" ]       # Проверка наличия файла.
then
    file_name=$1
else
    echo "Файл \"$1\" не найден."
    exit $E_NOFILE
fi
# =================================================================

MAXWIDTH=70          # Максимальная длина строки.

#  Удаление символов "^" начиная с первого символа строки,
#+ и ограничить длину строки 70-ю символами.
sed '
s/^&gt;//
s/^  *&gt;//
s/^  *//
s/              *//
' $1 | fold -s --width=$MAXWIDTH
          # ключ -s команды "fold" разрывает, если это возможно, строку по пробельному символу.

#  Этот сценарий был написан после прочтения статьи, в котором расхваливалась
#+ утилита под Windows, размером в 164K, с подобной функциональностью.
#
#  Хороший набор утилит для обработки текста и эффективный
#+ скриптовый язык -- это все, что необходимо, чтобы составить серьезную конкуренцию
#+ чрезмерно "раздутым" программам.

exit 0
</pre>
        </div>

        <div class="EXAMPLE">
          <a name="RN"></a>

          <p><strong>Пример A-3. rn: Очень простая утилита для
          переименования файлов</strong></p>

          <p>Этот сценарий является модификацией <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LOWERCASE">Пример 12-15</a>.</p>
<pre class="PROGRAMLISTING">#! /bin/bash
#
# Очень простая утилита для переименования файлов
#
#  Утилита "ren", автор Vladimir Lanin (lanin@csd2.nyu.edu),
#+ выполняет эти же действия много лучше.


ARGS=2
E_BADARGS=65
ONE=1                     # Единственное или множественное число (см. ниже).

if [ $# -ne "$ARGS" ]
then
  echo "Порядок использования: `basename $0` старый_шаблон новый_шаблон"
  # Например: "rn gif jpg", поменяет расширения всех файлов в текущем каталоге с gif на jpg.
  exit $E_BADARGS
fi

number=0                  # Количество переименованных файлов.


for filename in *$1*      # Проход по списку файлов в текущем каталоге.
do
   if [ -f "$filename" ]
   then
     fname=`basename $filename`            # Удалить путь к файлу из имени.
     n=`echo $fname | sed -e "s/$1/$2/"`   # Поменять старое имя на новое.
     mv $fname $n                          # Переименовать.
     let "number += 1"
   fi
done

if [ "$number" -eq "$ONE" ]                # Соблюдение правил грамматики.
then
 echo "$number файл переименован."
else
 echo "Переименовано файлов: $number."
fi

exit 0


# Упражнения:
# ----------
# С какими типами файлов этот сценарий не будет работать?
# Как это исправить?
#
#  Переделайте сценарий таким образом, чтобы он мог обрабатывать все файлы в каталоге,
#+ в именах которых содержатся пробелы, заменяя пробелы символом подчеркивания.
</pre>
        </div>

        <div class="EXAMPLE">
          <a name="BLANKRENAME"></a>

          <p><strong>Пример A-4. blank-rename: переименование файлов,
          чьи имена содержат пробелы</strong></p>

          <p>Это даже более простая версия предыдущего примера.</p>
<pre class="PROGRAMLISTING">#! /bin/bash
# blank-rename.sh
#
# Заменяет пробелы символом подчеркивания в именах файлов в текущем каталоге.

ONE=1                     # единственное или множественное число (см. ниже).
number=0                  # Количество переименованных файлов.
FOUND=0                   # Код завершения в случае успеха.

for filename in *         # Перебор всех файлов в текущем каталоге.
do
     echo "$filename" | grep -q " "         #  Проверить -- содержит ли имя файла
     if [ $? -eq $FOUND ]                   #+ пробелы.
     then
       fname=$filename                      # Удалить путь из имени файла.
       n=`echo $fname | sed -e "s/ /_/g"`   # Заменить пробелы символом подчеркивания.
       mv "$fname" "$n"                     # Переименование.
       let "number += 1"
     fi
done

if [ "$number" -eq "$ONE" ]
then
 echo "$number файл переименован."
else
 echo "Переименовано файлов: $number"
fi

exit 0
</pre>
        </div>

        <div class="EXAMPLE">
          <a name="ENCRYPTEDPW"></a>

          <p><strong>Пример A-5. encryptedpw: Передача файла на
          ftp-сервер, с использованием пароля</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# Модификация примера "ex72.sh", добавлено шифрование пароля.

#  Обратите внимание: этот вариант все еще нельзя считать безопасным,
#+ поскольку в сеть пароль уходит в незашифрованном виде.
# Используйте "ssh", если вас это беспокоит.

E_BADARGS=65

if [ -z "$1" ]
then
  echo "Порядок использования: `basename $0` имя_файла"
  exit $E_BADARGS
fi

Username=bozo           # Измените на свой.
pword=/home/bozo/secret/password_encrypted.file
# Файл, содержащий пароль в зашифрованном виде.

Filename=`basename $1`  # Удалить путь из имени файла

Server="XXX"
Directory="YYY"         # Подставьте фактические имя сервера и каталога.


Password=`cruft &lt;$pword`          # Расшифровка.
#  Используется авторская программа "cruft",
#+ основанная на алгоритме "onetime pad",
#+ ее можно скачать с :
#+ Primary-site:   ftp://ibiblio.org/pub/Linux/utils/file
#+                 cruft-0.2.tar.gz [16k]


ftp -n $Server &lt;&lt;End-Of-Session
user $Username $Password
binary
bell
cd $Directory
put $Filename
bye
End-Of-Session
# ключ -n, команды "ftp", запрещает автоматический вход.
# "bell" -- звонок (звуковой сигнал) после передачи каждого файла.

exit 0
</pre>
        </div>

        <div class="EXAMPLE">
          <a name="COPYCD"></a>

          <p><strong>Пример A-6. copy-cd: Копирование компакт-дисков с
          данными</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# copy-cd.sh: copying a data CD

CDROM=/dev/cdrom                           # устройство CD ROM
OF=/home/bozo/projects/cdimage.iso         # промежуточный файл
#       /xxxx/xxxxxxx/                     измените для своей системы.
BLOCKSIZE=2048
SPEED=2                                    # Можно задать более высокую скорость, если поддерживается.

echo; echo "Вставьте исходный CD, но *НЕ* монтируйте его."
echo "Нажмите ENTER, когда будете готовы. "
read ready                                 # Ожидание.

echo; echo "Создается промежуточный файл $OF."
echo "Это может занять какое-то время. Пожалуйста подождите."

dd if=$CDROM of=$OF bs=$BLOCKSIZE          # Копирование.


echo; echo "Выньте исходный CD."
echo "Вставьте чистую болванку CDR."
echo "Нажмите ENTER, когда будете готовы. "
read ready                                 # Ожидание.

echo "Копируется файл $OF на болванку."

cdrecord -v -isosize speed=$SPEED dev=0,0 $OF
# Используется пакет Joerg Schilling -- "cdrecord" .
# http://www.fokus.gmd.de/nthp/employees/schilling/cdrecord.html


echo; echo "Копирование завершено."

echo "Желаете удалить промежуточный файл (y/n)? "  # Наверняка большой файл получился.
read answer

case "$answer" in
[yY]) rm -f $OF
      echo "Файл $OF удален."
      ;;
*)    echo "Файл $OF не был удален.";;
esac

echo

# Упражнение:
# Добавьте в оператор "case" возможность обработки, введенных пользователем, "yes" и "Yes".

exit 0
</pre>
        </div>

        <div class="EXAMPLE">
          <a name="COLLATZ"></a>

          <p><strong>Пример A-7. Последовательности Коллаца
          (Collatz)</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# collatz.sh

#  Широко известная последовательность Коллаца (Collatz) (гипотеза Коллаца).
#  -------------------------------------------
#  1) Принимает из командной строки "начальное" целое число.
#  2) ЧИСЛО &lt;--- НАЧАЛЬНОЕ ЗНАЧЕНИЕ
#  3) Вывести ЧИСЛО.
#  4)  Если ЧИСЛО четное, разделить на 2,
#  5)+ Если не четное -- умножить на 3 и прибавить 1.
#  6) ЧИСЛО &lt;--- РЕЗУЛЬТАТ
#  7) Повторить, начиная с п. 3, заданное число раз.
#
#  Теоретически, такая последовательность должна сходиться,
#+ не зависимо от величины начального значения,
#+ к повторению циклов "4,2,1...",
#+ даже после значительных флуктуаций в самом начале.


MAX_ITERATIONS=200
# Для больших начальных значений (&gt;32000), это значение придется увеличить.

h=${1:-$$}                      #  Начальное значение
                                #  если из командной строки ничего не задано, то берется $PID,

echo
echo "C($h) --- $MAX_ITERATIONS итераций"
echo

for ((i=1; i&lt;=MAX_ITERATIONS; i++))
do

echo -n "$h     "
#          ^^^^^
#           табуляция

  let "remainder = h % 2"
  if [ "$remainder" -eq 0 ]   # Четное?
  then
    let "h /= 2"              # Разделить на 2.
  else
    let "h = h*3 + 1"         # Умножить на 3 и прибавить 1.
  fi


COLUMNS=10                    # Выводить по 10 значений в строке.
let "line_break = i % $COLUMNS"
if [ "$line_break" -eq 0 ]
then
  echo
fi

done

echo

exit 0
</pre>
        </div>

        <div class="EXAMPLE">
          <a name="DAYSBETWEEN"></a>

          <p><strong>Пример A-8. days-between: Подсчет числа дней между
          двумя датами</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# days-between.sh:    Подсчет числа дней между двумя датами.
# Порядок использования: ./days-between.sh [M]M/[D]D/YYYY [M]M/[D]D/YYYY

ARGS=2                # Ожидается два аргумента из командной строки.
E_PARAM_ERR=65        # Ошибка в числе ожидаемых аргументов.

REFYR=1600            # Начальный год.
CENTURY=100
DIY=365
ADJ_DIY=367           # Корректировка на високосный год + 1.
MIY=12
DIM=31
LEAPCYCLE=4

MAXRETVAL=255         # Максимально возможное возвращаемое значение
                      # для положительных чисел.

diff=                         # Количество дней между датами.
value=                # Абсолютное значение.
day=                  # день, месяц, год.
month=
year=


Param_Error ()        # Ошибка в пвраметрах командной строки.
{
  echo "Порядок использования: `basename $0` [M]M/[D]D/YYYY [M]M/[D]D/YYYY"
  echo "       (даты должны быть после 1/3/1600)"
  exit $E_PARAM_ERR
}


Parse_Date ()                 # Разбор даты.
{
  month=${1%%/**}
  dm=${1%/**}                 # День и месяц.
  day=${dm#*/}
  let "year = `basename $1`"  # Хотя это и не имя файла, но результат тот же.
}


check_date ()                 # Проверка даты.
{
  [ "$day" -gt "$DIM" ] || [ "$month" -gt "$MIY" ] || [ "$year" -lt "$REFYR" ] &amp;&amp; Param_Error
  # Выход из сценария при обнаружении ошибки.
  # Используется комбинация "ИЛИ-списка / И-списка".
  #
  # Упражнение: Реализуйте более строгую проверку даты.
}


strip_leading_zero () # Удалить ведущий ноль
{
  val=${1#0}          # иначе Bash будет считать числа
  return $val         # восьмеричными (POSIX.2, sect 2.9.2.1).
}


day_index ()          # Формула Гаусса:
{                     # Количество дней от 3 Янв. 1600 до заданной даты.

  day=$1
  month=$2
  year=$3

  let "month = $month - 2"
  if [ "$month" -le 0 ]
  then
    let "month += 12"
    let "year -= 1"
  fi

  let "year -= $REFYR"
  let "indexyr = $year / $CENTURY"


  let "Days = $DIY*$year + $year/$LEAPCYCLE - $indexyr + $indexyr/$LEAPCYCLE + $ADJ_DIY*$month/$MIY + $day - $DIM"
  # Более подробное объяснение алгоритма вы найдете в
  # http://home.t-online.de/home/berndt.schwerdtfeger/cal.htm


  if [ "$Days" -gt "$MAXRETVAL" ]  # Если больше 255,
  then                             # то поменять знак
    let "dindex = 0 - $Days"       # чтобы функция смогла вернуть полное значение.
  else let "dindex = $Days"
  fi

  return $dindex

}


calculate_difference ()            # Разница между двумя датами.
{
  let "diff = $1 - $2"             # Глобальная переменная.
}


abs ()                             # Абсолютное значение
{                                  # Используется глобальная переменная "value".
  if [ "$1" -lt 0 ]                # Если число отрицательное
  then                             # то
    let "value = 0 - $1"           # изменить знак,
  else                             # иначе
    let "value = $1"               # оставить как есть.
  fi
}



if [ $# -ne "$ARGS" ]              # Требуется два аргумента командной строки.
then
  Param_Error
fi

Parse_Date $1
check_date $day $month $year      # Проверка даты.

strip_leading_zero $day           # Удалить ведущие нули
day=$?                            # в номере дня и/или месяца.
strip_leading_zero $month
month=$?

day_index $day $month $year
date1=$?

abs $date1                         # Абсолютное значение
date1=$value

Parse_Date $2
check_date $day $month $year

strip_leading_zero $day
day=$?
strip_leading_zero $month
month=$?

day_index $day $month $year
date2=$?

abs $date2                         # Абсолютное значение
date2=$value

calculate_difference $date1 $date2

abs $diff                          # Абсолютное значение
diff=$value

echo $diff

exit 0
# Сравните этот сценарий с реализацией формулы Гаусса на C
# http://buschencrew.hypermart.net/software/datedif
</pre>
        </div>

        <div class="EXAMPLE">
          <a name="MAKEDICT"></a>

          <p><strong>Пример A-9. Создание <span class="QUOTE">"словаря"</span></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# makedict.sh  [создание словаря]

# Модификация сценария /usr/sbin/mkdict.
# Авторские права на оригинальный сценарий принадлежат Alec Muffett.
#
#  Этот модифицированный вариант включен в документ на основе
#+ документа "LICENSE" из пакета "Crack"
#+ с которым распространяется оригинальный сценарий.

#  Этот скрипт обрабатывает текстовые файлы и создает отсортированный список
#+ слов, найденных в этих файлах.
#  Он может оказаться полезным для сборки словарей
#+ и проведения лексикографического анализа.


E_BADARGS=65

if [ ! -r "$1" ]                     #  Необходим хотя бы один аргумент --
then                                 #+ имя файла.
  echo "Порядок использования: $0 имена_файлов"
  exit $E_BADARGS
fi


# SORT="sort"                        #  Необходимость задания ключей сортировки отпала.
                                     #+ Изменено, по отношению к оригинальному сценарию.

cat $* |                             # Выдать содержимое файлов на stdout.
        tr A-Z a-z |                 # Преобразовать в нижний регистр.
        tr ' ' '\012' |              # Новое: заменить пробелы символами перевода строки.
#       tr -cd '\012[a-z][0-9]' |    #  В оригинальном сценарии: удалить все символы,
                                     #+ которые не являются буквами или цифрами.
        tr -c '\012a-z'  '\012' |    #  Вместо удаления
                                     #+ неалфавитно-цифровые символы заменяются на перевод строки.
        sort |
        uniq |                       # Удалить повторяющиеся слова.
        grep -v '^#' |               # Удалить строки, начинающиеся с "#".
        grep -v '^$'                 # Удалить пустые строки.

exit 0
</pre>
        </div>

        <div class="EXAMPLE">
          <a name="SOUNDEX"></a>

          <p><strong>Пример A-10. Расчет индекса
          "созвучности"</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# soundex.sh: Расчет индекса "созвучности"

# =======================================================
#       Сценарий Soundex
#            Автор
#         Mendel Cooper
#     thegrendel@theriver.com
#       23 Января 2002 г.
#
#   Условия распространения: Public Domain.
#
# Несколько отличающаяся версия этого сценария была опубликована
#+ Эдом Шэфером (Ed Schaefer) в Июле 2002 года в колонке "Shell Corner"
#+ "Unix Review" on-line,
#+ http://www.unixreview.com/documents/uni1026336632258/
# =======================================================


ARGCOUNT=1                     # Требуется аргумент командной строки.
E_WRONGARGS=70

if [ $# -ne "$ARGCOUNT" ]
then
  echo "Порядок использования: `basename $0` имя"
  exit $E_WRONGARGS
fi


assign_value ()                #  Присвоить числовые значения
{                              #+ символам в имени.

  val1=bfpv                    # 'b,f,p,v' = 1
  val2=cgjkqsxz                # 'c,g,j,k,q,s,x,z' = 2
  val3=dt                      #  и т.п.
  val4=l
  val5=mn
  val6=r

# Попробуйте разобраться в том, что здесь происходит.

value=$( echo "$1" \
| tr -d wh \
| tr $val1 1 | tr $val2 2 | tr $val3 3 \
| tr $val4 4 | tr $val5 5 | tr $val6 6 \
| tr -s 123456 \
| tr -d aeiouy )

# Символам в имени присваиваются числовые значения.
# Удаляются повторяющиеся числа, если они не разделены гласными.
# Гласные игнорируются, если они не являются разделителями, которые удаляются в последнюю очередь.
# Символы 'w' и 'h' удаляются в первую очередь.
}


input_name="$1"
echo
echo "Имя = $input_name"


# Перевести все символы в имени в нижний регистр.
# ------------------------------------------------
name=$( echo $input_name | tr A-Z a-z )
# ------------------------------------------------


# Начальный символ в индекса "созвучия": первая буква в имени.
# --------------------------------------------


char_pos=0                     # Начальная позиция в имени.
prefix0=${name:$char_pos:1}
prefix=`echo $prefix0 | tr a-z A-Z`
                               # Первую букву в имени -- в верхний регистр.

let "char_pos += 1"            # Передвинуть "указатель" на один символ.
name1=${name:$char_pos}


# ++++++++++++++++++++++++++++ Исключение отдельных ситуаций +++++++++++++++++++++++++++++++
#  Теперь мы передвинулись на один символ вправо.
#  Если второй символ в имени совпадает с первым
#+ то его нужно отбросить.
#  Кроме того, мы должны проверить -- не является ли первый символ
#+ гласной, 'w' или 'h'.

char1=`echo $prefix | tr A-Z a-z`    # Первый символ -- в нижний регистр.

assign_value $name
s1=$value
assign_value $name1
s2=$value
assign_value $char1
s3=$value
s3=9$s3                              #  Если первый символ в имени -- гласная буква
                                     #+ или 'w' или 'h',
                                     #+ то ее "значение" нужно отбросить.
                                     #+ Поэтому ставим 9, или другое
                                     #+ неиспользуемое значение, которое можно будет проверить.


if [[ "$s1" -ne "$s2" || "$s3" -eq 9 ]]
then
  suffix=$s2
else
  suffix=${s2:$char_pos}
fi
# ++++++++++++++++++++++++ Конец исключения отдельных ситуаций +++++++++++++++++++++++++++++++


padding=000                    # Дополнить тремя нулями.


soun=$prefix$suffix$padding    # Нули добавить в конец получившегося индекса.

MAXLEN=4                       # Ограничить длину индекса 4-мя символами.
soundex=${soun:0:$MAXLEN}

echo "Индекс созвучия = $soundex"

echo

#  Индекс "созвучия" - это метод индексации и классификации имен
#+ по подобию звучания.
#  Индекс "созвучия" начинается с первого символа в имени,
#+ за которым следуют 3-значный расчетный код.
#  Имена, которые произносятся примерно одинаково, имеют близкие индексы "созвучия".

#   Например:
#   Smith и Smythe -- оба имеют индекс "созвучия" "S530".
#   Harrison = H625
#   Hargison = H622
#   Harriman = H655

#  Как правило эта методика дает неплохой результат, но имеются и аномалии.
#
#
#  Дополнительную информацию вы найдете на
#+ "National Archives and Records Administration home page",
#+ http://www.nara.gov/genealogy/soundex/soundex.html



# Упражнение:
# ----------
# Упростите блок "Исключение отдельных ситуаций" .

exit 0
</pre>
        </div>

        <div class="EXAMPLE">
          <a name="LIFESLOW"></a>

          <p><strong>Пример A-11. <span class="QUOTE">"Игра
          "Жизнь""</span></strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# life.sh: Игра "Жизнь"

# ##################################################################### #
# Это Bash-версия известной игры Джона Конвея (John Conway) "Жизнь".    #
# --------------------------------------------------------------------- #
# Прямоугольное игровое поле разбито на ячейки, в каждой ячейке может   #
#+ располагаться живая особь.                                           #
# Соответственно, ячейка с живой особью отмечается точкой,              #
#+ не занятая ячейка -- остается пустой.                                #
#  Изначально, ячейки заполняются из файла --                           #
#+ это первое поколение, или "поколение 0"                              #
# Воспроизводство особей, в каждом последующем поколении,               #
#+ определяется следующими правилами                                    #
# 1) Каждая ячейка имеет "соседей"                                      #
#+   слева, справа, сверху, снизу и 4 по диагоналям.                    #
#                       123                                             #
#                       4*5                                             #
#                       678                                             #
#                                                                       #
# 2) Если живая особь имеет 2 или 3 живых соседей, то она остается жить.#
# 3) Если пустая ячейка имеет 3 живых соседей --                        #
#+   в ней "рождается" новая особь                                      #
SURVIVE=2                                                               #
BIRTH=3                                                                 #
# 4) В любом другом случае, живая особь "погибает"                      #
# ##################################################################### #


startfile=gen0   # Начальное поколение из файла по-умолчанию -- "gen0".
                 # если не задан другой файл, из командной строки.
                 #
if [ -n "$1" ]   # Проверить аргумент командной строки -- файл с "поколениемn 0".
then
  if [ -e "$1" ] # Проверка наличия файла.
  then
    startfile="$1"
  fi
fi


ALIVE1=.
DEAD1=_
                 # Представление "живых" особей и пустых ячеек в файле с "поколением 0".

#  Этот сценарий работает с игровым полем 10 x 10 grid (может быть увеличено,
#+ но большое игровое поле будет обрабатываться очень медленно).
ROWS=10
COLS=10

GENERATIONS=10          #  Максимальное число поколений.

NONE_ALIVE=80           #  Код завершения на случай,
                        #+ если не осталось ни одной "живой" особи.
TRUE=0
FALSE=1
ALIVE=0
DEAD=1

avar=                   # Текущее поколение.
generation=0            # Инициализация счетчика поколений.

# =================================================================


let "cells = $ROWS * $COLS"
                        # Количество ячеек на игровом поле.

declare -a initial      # Массивы ячеек.
declare -a current

display ()
{

alive=0                 # Количество "живых" особей.
                        # Изначально -- ноль.

declare -a arr
arr=( `echo "$1"` )     # Преобразовать аргумент в массив.

element_count=${#arr[*]}

local i
local rowcheck

for ((i=0; i&lt;$element_count; i++))
do

  # Символ перевода строки -- в конец каждой строки.
  let "rowcheck = $i % ROWS"
  if [ "$rowcheck" -eq 0 ]
  then
    echo                # Перевод строки.
    echo -n "      "    # Выравнивание.
  fi

  cell=${arr[i]}

  if [ "$cell" = . ]
  then
    let "alive += 1"
  fi

  echo -n "$cell" | sed -e 's/_/ /g'
  # Вывести массив, по пути заменяя символы подчеркивания на пробелы.
done

return

}

IsValid ()                            # Проверка корректности координат ячейки.
{

  if [ -z "$1"  -o -z "$2" ]          # Проверка наличия входных аргументов.
  then
    return $FALSE
  fi

local row
local lower_limit=0                   # Запрет на отрицательные координаты.
local upper_limit
local left
local right

let "upper_limit = $ROWS * $COLS - 1" # Номер последней ячейки на игровом поле.


if [ "$1" -lt "$lower_limit" -o "$1" -gt "$upper_limit" ]
then
  return $FALSE                       # Выход за границы массива.
fi

row=$2
let "left = $row * $ROWS"             # Левая граница.
let "right = $left + $COLS - 1"       # Правая граница.

if [ "$1" -lt "$left" -o "$1" -gt "$right" ]
then
  return $FALSE                       # Выхол за нижнюю строку.
fi

return $TRUE                          # Координаты корректны.

}


IsAlive ()              # Проверка наличия "живой" особи в ячейке.
                        # Принимает массив и номер ячейки в качестве входных аргументов.
{
  GetCount "$1" $2      # Подсчитать кол-во "живых" соседей.
  local nhbd=$?


  if [ "$nhbd" -eq "$BIRTH" ]  # "Живая".
  then
    return $ALIVE
  fi

  if [ "$3" = "." -a "$nhbd" -eq "$SURVIVE" ]
  then                  # "Живая" если перед этим была "живая".
    return $ALIVE
  fi

  return $DEAD          # По-умолчанию.

}


GetCount ()             # Подсчет "живых" соседей.
                        # Необходимо 2 аргумента:
                        # $1) переменная-массив
                        # $2) cell номер ячейки
{
  local cell_number=$2
  local array
  local top
  local center
  local bottom
  local r
  local row
  local i
  local t_top
  local t_cen
  local t_bot
  local count=0
  local ROW_NHBD=3

  array=( `echo "$1"` )

  let "top = $cell_number - $COLS - 1"    # Номера соседних ячеек.
  let "center = $cell_number - 1"
  let "bottom = $cell_number + $COLS - 1"
  let "r = $cell_number / $ROWS"

  for ((i=0; i&lt;$ROW_NHBD; i++))           # Просмотр слева-направо.
  do
    let "t_top = $top + $i"
    let "t_cen = $center + $i"
    let "t_bot = $bottom + $i"


    let "row = $r"                        # Пройти по соседям в средней строке.
    IsValid $t_cen $row                   # Координаты корректны?
    if [ $? -eq "$TRUE" ]
    then
      if [ ${array[$t_cen]} = "$ALIVE1" ] # "Живая"?
      then                                # Да!
        let "count += 1"                  # Нарастить счетчик.
      fi
    fi

    let "row = $r - 1"                    # По верхней строке.
    IsValid $t_top $row
    if [ $? -eq "$TRUE" ]
    then
      if [ ${array[$t_top]} = "$ALIVE1" ]
      then
        let "count += 1"
      fi
    fi

    let "row = $r + 1"                    # По нижней строке.
    IsValid $t_bot $row
    if [ $? -eq "$TRUE" ]
    then
      if [ ${array[$t_bot]} = "$ALIVE1" ]
      then
        let "count += 1"
      fi
    fi

  done


  if [ ${array[$cell_number]} = "$ALIVE1" ]
  then
    let "count -= 1"        #  Убедиться, что сама проверяемая ячейка
  fi                        #+ не была подсчитана.


  return $count

}

next_gen ()               # Обновить массив, в котором содержится информация о новом "поколении".
{

local array
local i=0

array=( `echo "$1"` )     # Преобразовать в массив.

while [ "$i" -lt "$cells" ]
do
  IsAlive "$1" $i ${array[$i]}   # "Живая"?
  if [ $? -eq "$ALIVE" ]
  then                           #  Если "живая", то
    array[$i]=.                  #+ записать точку.
  else
    array[$i]="_"                #  Иначе -- символ подчеркивания
   fi                            #+ (который позднее заменится на пробел).
  let "i += 1"
done


# let "generation += 1"   # Увеличить счетчик поколений.

# Подготовка переменных, для передачи в функцию "display".
avar=`echo ${array[@]}`   # Преобразовать массив в строку.
display "$avar"           # Вывести его.
echo; echo
echo "Поколение $generation -- живых особей $alive"

if [ "$alive" -eq 0 ]
then
  echo
  echo "Преждеверменное завершение: не осталось ни одной живой особи!"
  exit $NONE_ALIVE        #  Нет смысла продолжать
fi                        #+ если не осталось ни одной живой особи

}


# =========================================================

# main ()

# Загрузить начальное поколение из файла.
initial=( `cat "$startfile" | sed -e '/#/d' | tr -d '\n' |\
sed -e 's/\./\. /g' -e 's/_/_ /g'` )
# Удалить строки, начинающиеся с символа '#' -- комментарии.
# Удалить строки перевода строки и вставить пробелы между элементами.

clear          # Очистка экрана.

echo #       Заголовок
echo "======================="
echo "    $GENERATIONS поколений"
echo "           в"
echo "      игре \" ЖИЗНЬ\""
echo "======================="


# -------- Вывести первое поколение. --------
Gen0=`echo ${initial[@]}`
display "$Gen0"           # Тлько вывод.
echo; echo
echo "Поколение $generation -- живых особей $alive"
# -------------------------------------------


let "generation += 1"     # Нарастить счетчик поколений.
echo

# ------- Вывести второе поколение. -------
Cur=`echo ${initial[@]}`
next_gen "$Cur"          # Обновить и вывести.
# ------------------------------------------

let "generation += 1"     # Нарастить счетчик поколений.

# ------ Основной цикл игры ------
while [ "$generation" -le "$GENERATIONS" ]
do
  Cur="$avar"
  next_gen "$Cur"
  let "generation += 1"
done
# ==============================================================

echo

exit 0

# --------------------------------------------------------------
# Этот сценарий имеет недоработку.
# Граничные ячейки сверху, снизу и сбоков  остаются пустыми.
# Упражнение: Доработайте сценарий таким образом, чтобы ,
# +         левая и правая стороны как бы "соприкасались",
# +         так же и верхняя и нижняя стороны.
</pre>
        </div>

        <div class="EXAMPLE">
          <a name="GEN0DATA"></a>

          <p><strong>Пример A-12. Файл с первым поколением для игры
          <span class="QUOTE">"Жизнь"</span></strong></p>
<pre class="PROGRAMLISTING"># Это файл-пример, содержащий "поколение 0", для сценария "life.sh".
# --------------------------------------------------------------
#  Игровое поле имеет размер 10 x 10, точкой обозначается "живая" особь,
#+ символом подчеркивания -- пустая ячейка. Мы не можем использовать пробелы,
#+ для обозначения пустых ячеек, из-за особенностей строения массивов в Bash.
#  [Упражнение для читателей: объясните, почему?.]
#
# Строки, начинающиеся с символа '#' считаются комментариями, сценарий их игнорирует.
__.__..___
___._.____
____.___..
_._______.
____._____
..__...___
____._____
___...____
__.._..___
_..___..__
</pre>
        </div>

        <p>+++</p>

        <p>Следующие два сценария предоставил Mark Moraes, из
        университета в Торонто. См. файл <span class="QUOTE">"Moraes-COPYRIGHT"</span>, который
        содержит указание на авторские права.</p>

        <div class="EXAMPLE">
          <a name="BEHEAD"></a>

          <p><strong>Пример A-13. behead: Удаление заголовков из
          электронных писем и новостей</strong></p>
<pre class="PROGRAMLISTING">#! /bin/sh
# Удаление заголовков из электронных писем и новостей т.е. до первой
# пустой строки
# Mark Moraes, Университет в Торонто

# ==&gt; Такие комментарии добавлены автором документа.

if [ $# -eq 0 ]; then
# ==&gt; Если входной аргумент не задан (файл), то выводить результат на stdin.
        sed -e '1,/^$/d' -e '/^[        ]*$/d'
        # --&gt; Удалить пустые строки и все строки предшествующие им
else
# ==&gt; Если аргумент командной строки задан, то использовать его как имя файла.
        for i do
                sed -e '1,/^$/d' -e '/^[        ]*$/d' $i
                # --&gt; То же, что и выше.
        done
fi

# ==&gt; Упражнение: Добавьте проверку на наличие ошибок.
# ==&gt;
# ==&gt; Обратите внимание -- как похожи маленькие сценарии sed, за исключением передачи аргумента.
# ==&gt; Можно ли его оформит в виде функции? Почему да или почему нет?
</pre>
        </div>

        <div class="EXAMPLE">
          <a name="FTPGET"></a>

          <p><strong>Пример A-14. ftpget: Скачивание файлов по
          ftp</strong></p>
<pre class="PROGRAMLISTING">#! /bin/sh
# $Id: ftpget,v 1.2 91/05/07 21:15:43 moraes Exp $
# Сценарий устанавливает анонимное соединение с ftp-сервером.
# Простой и быстрый - написан как дополнение к ftplist
# -h -- удаленный сервер (по-умолчанию prep.ai.mit.edu)
# -d -- каталог на сервере - вы можете указать последовательность из нескольких ключей -d
# Если вы используете относительные пути,
# будьте внимательны при задании последовательности.
# (по-умолчанию -- каталог пользователя ftp)
# -v -- "многословный" режим, будет показывать все ответы ftp-сервера
# -f -- file[:localfile] скачивает удаленный file и записывает под именем localfile
# -m -- шаблон для mget. Не забудьте взять в кавычки!
# -c -- локальный каталог
# Например,
#       ftpget -h expo.lcs.mit.edu -d contrib -f xplaces.shar:xplaces.sh \
#               -d ../pub/R3/fixes -c ~/fixes -m 'fix*'
# Эта команда загрузит файл xplaces.shar из ~ftp/contrib с expo.lcs.mit.edu
# и сохранит под именем xplaces.sh в текущем каталоге, затем заберет все исправления (fixes)
# из ~ftp/pub/R3/fixes и поместит их в каталог ~/fixes.
# Очевидно, что последовательность ключей и аргументов очень важна, поскольку
# она определяет последовательность операций, выполняемых с удаленным ftp-сервером
#
# Mark Moraes (moraes@csri.toronto.edu), Feb 1, 1989
#


# ==&gt; Эти комментарии добавлены автором документа.

# PATH=/local/bin:/usr/ucb:/usr/bin:/bin
# export PATH
# ==&gt; Первые две строки в оригинальном сценарии вероятно излишни.

TMPFILE=/tmp/ftp.$$
# ==&gt; Создан временный файл

SITE=`domainname`.toronto.edu
# ==&gt; 'domainname' подобен 'hostname'

usage="Порядок использования: $0 [-h удаленный_сервер] [-d удаленный_каталог]... [-f удаленный_файл:локальный_файл]... \
                [-c локальный_каталог] [-m шаблон_имен_файлов] [-v]"
ftpflags="-i -n"
verbflag=
set -f          # разрешить подстановку имен файлов (globbing) для опции -m
set x `getopt vh:d:c:m:f: $*`
if [ $? != 0 ]; then
        echo $usage
        exit 65
fi
shift
trap 'rm -f ${TMPFILE} ; exit' 0 1 2 3 15
echo "user anonymous ${USER-gnu}@${SITE} &gt; ${TMPFILE}"
# ==&gt; Добавлены кавычки (рекомендуется).
echo binary &gt;&gt; ${TMPFILE}
for i in $*   # ==&gt; Разбор командной строки.
do
        case $i in
        -v) verbflag=-v; echo hash &gt;&gt; ${TMPFILE}; shift;;
        -h) remhost=$2; shift 2;;
        -d) echo cd $2 &gt;&gt; ${TMPFILE};
            if [ x${verbflag} != x ]; then
                echo pwd &gt;&gt; ${TMPFILE};
            fi;
            shift 2;;
        -c) echo lcd $2 &gt;&gt; ${TMPFILE}; shift 2;;
        -m) echo mget "$2" &gt;&gt; ${TMPFILE}; shift 2;;
        -f) f1=`expr "$2" : "\([^:]*\).*"`; f2=`expr "$2" : "[^:]*:\(.*\)"`;
            echo get ${f1} ${f2} &gt;&gt; ${TMPFILE}; shift 2;;
        --) shift; break;;
        esac
done
if [ $# -ne 0 ]; then
        echo $usage
        exit 65   # ==&gt; В оригинале было "exit 2", изменено в соответствии со стандартами.
fi
if [ x${verbflag} != x ]; then
        ftpflags="${ftpflags} -v"
fi
if [ x${remhost} = x ]; then
        remhost=prep.ai.mit.edu
        # ==&gt; Здесь можете указать свой ftp-сервер по-умолчанию.
fi
echo quit &gt;&gt; ${TMPFILE}
# ==&gt; Все команды сохранены во временном файле.

ftp ${ftpflags} ${remhost} &lt; ${TMPFILE}
# ==&gt; Теперь обработать пакетный файл.

rm -f ${TMPFILE}
# ==&gt; В заключение, удалить временный файл (можно скопировать его в системный журнал).


# ==&gt; Упражнения:
# ==&gt; ----------
# ==&gt; 1) Добавьте обработку ошибок.
# ==&gt; 2) Добавьте уведомление звуковым сигналом.
</pre>
        </div>

        <div class="EXAMPLE">
          <a name="MORCOPY"></a>

          <p><strong>Пример A-15. Указание на авторские
          права</strong></p>
<pre class="PROGRAMLISTING">Следующее соглащение об авторских правах относится к двум, включенным в книгу,
сценариям от Mark Moraes: "behead.sh" и "ftpget.sh"

/*
 * Copyright University of Toronto 1988, 1989.
 * Автор: Mark Moraes
 *
 * Автор дает право на использование этого программного обеспечения
 * его изменение и рапространение со следующими ограничениями:
 *
 * 1. Автор и Университет Торонто не отвечают
 *    за последствия использования этого программного обеспечения,
 *    какими ужасными бы они ни были,
 *    даже если они вызваны ошибками в нем.
 *
 * 2. Указание на происхождение программного обеспечения не должно подвергаться изменениям,
 *    явно или по оплошности. Так как некоторые пользователи обращаются к исходным текстам,
 *    они обязательно должны быть включены в документацию.
 *
 * 3. Измененная версия должна содержать явное упоминание об этом и не должна
 *    выдаваться за оригинал. Так как некоторые пользователи обращаются к исходным текстам,
 *    они обязательно должны быть включены в документацию.
 *
 * 4. Это соглашение не может удаляться и/или изменяться.
 */
</pre>
        </div>

        <p>+</p>

        <p>Antek Sawicki предоставил следующий сценарий, который
        демонстрирует операцию подстановки параметров, обсуждавшуюся в
        <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PARAMETER-SUBSTITUTION">Section 9.3</a>.</p>

        <div class="EXAMPLE">
          <a name="PW"></a>

          <p><strong>Пример A-16. password: Генератор случайного 8-ми
          символьного пароля</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Для старых систем может потребоваться указать  #!/bin/bash2.
#
# Генератор случайных паролей для bash 2.x
# Автор: Antek Sawicki &lt;tenox@tenox.tc&gt;,
# который великодушно позволил использовать его в данном документе.
#
# ==&gt; Комментарии, добавленные автором документа ==&gt;


MATRIX="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
LENGTH="8"
# ==&gt; 'LENGTH' можно увеличить, для генерации более длинных паролей.


while [ "${n:=1}" -le "$LENGTH" ]
# ==&gt; Напоминаю, что ":=" -- это оператор "подстановки значения по-умолчанию".
# ==&gt; Таким образом, если 'n' не инициализирована, то в нее заносится 1.
do
        PASS="$PASS${MATRIX:$(($RANDOM%${#MATRIX})):1}"
        # ==&gt; Хитро, хитро....

        # ==&gt; Начнем с самых внутренних скобок...
        # ==&gt; ${#MATRIX} -- возвращает длину массива MATRIX.

        # ==&gt; $RANDOM%${#MATRIX} -- возвращает случайное число
        # ==&gt; в диапазоне 1 .. ДЛИНА_МАССИВА(MATRIX) - 1.

        # ==&gt; ${MATRIX:$(($RANDOM%${#MATRIX})):1}
        # ==&gt; возвращает символ из MATRIX, из случайной позиции (найденной выше).
        # ==&gt; См. подстановку параметров {var:pos:len} в Разделе 3.3.1
        # ==&gt; и примеры в этом разделе.

        # ==&gt; PASS=... -- добавление символа к строке PASS, полученной на предыдущих итерациях.

        # ==&gt; Чтобы детальнее проследить ход работы цикла, раскомментируйте следующую строку
        # ==&gt;             echo "$PASS"
        # ==&gt; Вы увидите, как на каждом проходе цикла,
        # ==&gt; к строке PASS добавляется по одному символу.

        let n+=1
        # ==&gt; Увеличить 'n' перед началом следующей итерации.
done

echo "$PASS"      # ==&gt; Или перенаправьте в файл, если пожелаете.

exit 0
</pre>
        </div>

        <p>+</p>

        <p>James R. Van Zandt предоставил следующий сценарий, который
        демонстрирует применение именованных каналов, по его словам,
        <span class="QUOTE">"на самом деле -- упражнение на применение
        кавычек и на экранирование"</span>.</p>

        <div class="EXAMPLE">
          <a name="FIFO"></a>

          <p><strong>Пример A-17. fifo: Создание резервных копий с
          помощью именованных каналов</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# ==&gt; Автор:James R. Van Zandt
# ==&gt; используется с его разрешения.

# ==&gt; Комментарии, добавленные автором документа.


  HERE=`uname -n`    # ==&gt; hostname
  THERE=bilbo
  echo "начало создания резервной копии на $THERE, за `date +%r`"
  # ==&gt; `date +%r` возвращает время в 12-ти часовом формате, т.е. "08:08:34 PM".

  # убедиться в том, что /pipe -- это действительно канал, а не простой файл
  rm -rf /pipe
  mkfifo /pipe       # ==&gt; Создание "именованного канала", с именем "/pipe".

  # ==&gt; 'su xyz' -- запускает команду от имени порльзователя "xyz".
  # ==&gt; 'ssh' -- вызов secure shell (вход на удаленную систему).
  su xyz -c "ssh $THERE \"cat &gt;/home/xyz/backup/${HERE}-daily.tar.gz\" &lt; /pipe"&amp;
  cd /
  tar -czf - bin boot dev etc home info lib man root sbin share usr var &gt;/pipe
  # ==&gt; Именованный канал /pipe, используется для передачи данных между процессами:
  # ==&gt; 'tar/gzip' пишет в /pipe, а 'ssh' -- читает из /pipe.

  # ==&gt; В результате будет получена резервная копия всех основных каталогов.

  # ==&gt; В чем состоит преимущество именованного канала, в данной ситуации,
        # ==&gt; перед неименованным каналом "|" ?
  # ==&gt; Будет ли работать неименованный канал в данной ситуации?


  exit 0
</pre>
        </div>

        <p>+</p>

        <p>Stephane Chazelas предоставил следующий сценарий, который
        демонстрирует возможность генерации простых чисел без
        использования массивов.</p>

        <div class="EXAMPLE">
          <a name="PRIMES"></a>

          <p><strong>Пример A-18. Генерация простых чисел, с
          использованием оператора деления по модулю (остаток от
          деления)</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# primes.sh: Генерация простых чисел, без использования массивов.
# Автор: Stephane Chazelas.

#  Этот сценарий не использует класический алгоритм "Решето Эратосфена",
#+ вместо него используется более понятный метод проверки каждого кандидата в простые числа
#+ путем поиска делителей, с помощью оператора нахождения остатка от деления "%".


LIMIT=1000                    # Простые от 2 до 1000

Primes()
{
 (( n = $1 + 1 ))             # Перейти к следующему числу.
 shift                        # Следующий параметр в списке.
#  echo "_n=$n i=$i_"

 if (( n == LIMIT ))
 then echo $*
 return
 fi

 for i; do                    # "i" устанавливается в "@", предыдущее значение $n.
#   echo "-n=$n i=$i-"
   (( i * i &gt; n )) &amp;&amp; break   # Оптимизация.
   (( n % i )) &amp;&amp; continue    # Отсечь составное число с помощью оператора "%".
   Primes $n $@               # Рекурсивный вызов внутри цикла.
   return
   done

   Primes $n $@ $n            # Рекурсивный вызов за пределами цикла.
                              # Последовательное накопление позиционных параметров.
                              # в "$@" накапливаются простые числа.
}

Primes 1

exit 0

# Раскомментарьте строки 16 и 24, это поможет понять суть происходящего.

# Сравните скоростные характеристики этого сценария и сценария (ex68.sh),
# реализующего алгоритм "Решето Эратосфена".

# Упражнение: Попробуйте реализовать этот сценарий без использования рекурсии.
#             Это даст некоторый выигрыш в скорости.
</pre>
        </div>

        <p>+</p>

        <p>Jordi Sanfeliu дал согласие на публикацию своего сценария
        <span class="emphasis"><em class="EMPHASIS">tree</em></span>.</p>

        <div class="EXAMPLE">
          <a name="TREE"></a>

          <p><strong>Пример A-19. tree: Вывод дерева
          каталогов</strong></p>
<pre class="PROGRAMLISTING">#!/bin/sh
#         @(#) tree      1.1  30/11/95       by Jordi Sanfeliu
#                                         email: mikaku@fiwix.org
#
#         Начальная версия:  1.0  30/11/95
#         Следующая версия:  1.1  24/02/97   Now, with symbolic links
#         Исправления     :  Ian Kjos, поддержка недоступных каталогов
#                           email: beth13@mail.utexas.edu
#
#         Tree -- средство просмотра дерева каталогов (очевидно :-) )
#

# ==&gt; Используется в данном документе с разрешения автора сценария, Jordi Sanfeliu.
# ==&gt; Комментарии, добавленные автором документа.
# ==&gt; Добавлено "окавычивание" аргументов.


search () {
   for dir in `echo *`
   # ==&gt; `echo *` список всех файлов в текущем каталоге, без символов перевода строки.
   # ==&gt; Тот же эффект дает     for dir in *
   # ==&gt; но "dir in `echo *`" не обрабатывет файлы, чьи имена содержат пробелы.
   do
      if [ -d "$dir" ] ; then   # ==&gt; Если это каталог (-d)...
         zz=0   # ==&gt; Временная переменная, для сохранения уровня вложенности каталога.
         while [ $zz != $deep ]    # Keep track of inner nested loop.
         do
            echo -n "|   "    # ==&gt; Показать символ вертикальной связи,
                              # ==&gt; с 2 пробелами и без перевода строки.
            zz=`expr $zz + 1` # ==&gt; Нарастить zz.
         done
         if [ -L "$dir" ] ; then   # ==&gt; Если символическая ссылка на каталог...
            echo "+---$dir" `ls -l $dir | sed 's/^.*'$dir' //'`
            # ==&gt; Показать горизонтальный соединитель и имя связянного каталога, но...
            # ==&gt; без указания даты/времени.
         else
            echo "+---$dir"      # ==&gt; Вывести горизонтальный соединитель...
                                 # ==&gt; и название каталога.
            if cd "$dir" ; then  # ==&gt; Если можно войти в каталог...
               deep=`expr $deep + 1`   # ==&gt; Нарастить уровень вложенности.
               search     # рекурсия ;-)
               numdirs=`expr $numdirs + 1`   # ==&gt; Нарастить счетчик каталогов.
            fi
         fi
      fi
   done
   cd ..   # ==&gt; Подняться на один уровень вверх.
   if [ "$deep" ] ; then  # ==&gt; Если depth = 0 (возвращает TRUE)...
      swfi=1              # ==&gt; выставить признак окончания поиска.
   fi
   deep=`expr $deep - 1`  # ==&gt; Уменьшить уровень вложенности.
}

# - Main -
if [ $# = 0 ] ; then
   cd `pwd`    # ==&gt; Если аргумент командной строки отсутствует, то используется текущий каталог.
else
   cd $1       # ==&gt; иначе перейти в заданный каталог.
fi
echo "Начальный каталог = `pwd`"
swfi=0      # ==&gt; Признак завершения поиска.
deep=0      # ==&gt; Уровень вложенности.
numdirs=0
zz=0

while [ "$swfi" != 1 ]   # Пока поиск не закончен...
do
   search   # ==&gt; Вызвать функцию поиска.
done
echo "Всего каталогов = $numdirs"

exit 0
# ==&gt; Попробуйте разобраться в том как этот сценарий работает.
</pre>
        </div>

        <p>Noah Friedman дал разрешение на публикацию своей библиотеки
        <span class="emphasis"><em class="EMPHASIS">функций для работы со строками</em></span>,
        которая, по сути, воспроизводит некоторые библиотечные функции
        языка C.</p>

        <div class="EXAMPLE">
          <a name="STRING"></a>

          <p><strong>Пример A-20. Функции для работы со
          строками</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash

# string.bash --- эмуляция библиотеки функций string(3)
# Автор: Noah Friedman &lt;friedman@prep.ai.mit.edu&gt;
# ==&gt;     Используется с его разрешения.
# Дата создания: 1992-07-01
# Дата последней модификации: 1993-09-29
# Public domain

# Преобразование в синтаксис bash v2 выполнил Chet Ramey

# Комментарий:
# Код:

#:docstring strcat:
# Порядок использования: strcat s1 s2
#
# Strcat добавляет содержимое переменной s2 к переменной s1.
#
# Пример:
#    a="foo"
#    b="bar"
#    strcat a b
#    echo $a
#    =&gt; foobar
#
#:end docstring:

###;;;autoload
function strcat ()
{
    local s1_val s2_val

    s1_val=${!1}                        # косвенная ссылка
    s2_val=${!2}
    eval "$1"=\'"${s1_val}${s2_val}"\'
    # ==&gt; eval $1='${s1_val}${s2_val}' во избежание проблем,
    # ==&gt; если одна из переменных содержит одиночную кавычку.
}

#:docstring strncat:
# Порядок использования: strncat s1 s2 $n
#
# Аналог strcat, но добавляет не более n символов из
# переменной s2. Результат выводится на stdout.
#
# Пример:
#    a=foo
#    b=barbaz
#    strncat a b 3
#    echo $a
#    =&gt; foobar
#
#:end docstring:

###;;;autoload
function strncat ()
{
    local s1="$1"
    local s2="$2"
    local -i n="$3"
    local s1_val s2_val

    s1_val=${!s1}                       # ==&gt; косвенная ссылка
    s2_val=${!s2}

    if [ ${#s2_val} -gt ${n} ]; then
       s2_val=${s2_val:0:$n}            # ==&gt; выделение подстроки
    fi

    eval "$s1"=\'"${s1_val}${s2_val}"\'
    # ==&gt; eval $1='${s1_val}${s2_val}' во избежание проблем,
    # ==&gt; если одна из переменных содержит одиночную кавычку.
}

#:docstring strcmp:
# Порядок использования: strcmp $s1 $s2
#
# Strcmp сравнивает две строки и возвращает число меньше, равно
# или больше нуля, в зависимости от результатов сравнения.
#:end docstring:

###;;;autoload
function strcmp ()
{
    [ "$1" = "$2" ] &amp;&amp; return 0

    [ "${1}" '&lt;' "${2}" ] &gt; /dev/null &amp;&amp; return -1

    return 1
}

#:docstring strncmp:
# Порядок использования: strncmp $s1 $s2 $n
#
# Подобна strcmp, но сравнивает не более n символов
#:end docstring:

###;;;autoload
function strncmp ()
{
    if [ -z "${3}" -o "${3}" -le "0" ]; then
       return 0
    fi

    if [ ${3} -ge ${#1} -a ${3} -ge ${#2} ]; then
       strcmp "$1" "$2"
       return $?
    else
       s1=${1:0:$3}
       s2=${2:0:$3}
       strcmp $s1 $s2
       return $?
    fi
}

#:docstring strlen:
# Порядок использования: strlen s
#
# возвращает количество символов в строке s.
#:end docstring:

###;;;autoload
function strlen ()
{
    eval echo "\${#${1}}"
    # ==&gt; Возвращает длину переменной,
    # ==&gt; чье имя передается как аргумент.
}

#:docstring strspn:
# Порядок использования: strspn $s1 $s2
#
# Strspn возвращает максимальную длину сегмента в строке s1,
# который полностью состоит из символов строки s2.
#:end docstring:

###;;;autoload
function strspn ()
{
    # Сброс содержимого переменной IFS позволяет обрабатывать пробелы как обычные символы.
    local IFS=
    local result="${1%%[!${2}]*}"

    echo ${#result}
}

#:docstring strcspn:
# Порядок использования: strcspn $s1 $s2
#
# Strcspn возвращает максимальную длину сегмента в строке s1,
# который полностью не содержит символы из строки s2.
#:end docstring:

###;;;autoload
function strcspn ()
{
    # Сброс содержимого переменной IFS позволяет обрабатывать пробелы как обычные символы.
    local IFS=
    local result="${1%%[${2}]*}"

    echo ${#result}
}

#:docstring strstr:
# Порядок использования: strstr s1 s2
#
# Strstr выводит подстроку первого вхождения строки s2
# в строке s1, или ничего не выводит, если подстрока s2 в строке s1 не найдена.
# Если s2 содержит строку нулевой длины, то strstr выводит строку s1.
#:end docstring:

###;;;autoload
function strstr ()
{
    # Если s2 -- строка нулевой длины, то вывести строку s1
    [ ${#2} -eq 0 ] &amp;&amp; { echo "$1" ; return 0; }

    # не выводить ничего, если s2 не найдена в s1
    case "$1" in
    *$2*) ;;
    *) return 1;;
    esac

    # использовать шаблон, для удаления всех несоответствий после s2 в s1
    first=${1/$2*/}

    # Затем удалить все несоответствия с начала строки
    echo "${1##$first}"
}

#:docstring strtok:
# Порядок использования: strtok s1 s2
#
# Strtok рассматривает строку s1, как последовательность из 0, или более,
# лексем (токенов), разделенных символами строки s2
# При первом вызове (с непустым аргументом s1)
# выводит первую лексему на stdout.
# Функция запоминает свое положение в строке s1 от вызова к вызову,
# так что последующие вызовы должны производиться с пустым первым аргументом,
# чтобы продолжить выделение лексем из строки s1.
# После вывода последней лексемы, все последующие вызовы будут выводить на stdout
# пустое значение. Строка-разделитель может изменяться от вызова к вызову.
#:end docstring:

###;;;autoload
function strtok ()
{
 :
}

#:docstring strtrunc:
# Порядок использования: strtrunc $n $s1 {$s2} {$...}
#
# Используется многими функциями, такими как strncmp, чтобы отсечь "лишние" символы.
# Выводит первые n символов в каждой из строк s1 s2 ... на stdout.
#:end docstring:

###;;;autoload
function strtrunc ()
{
    n=$1 ; shift
    for z; do
        echo "${z:0:$n}"
    done
}

# provide string

# string.bash конец библиотеки


# ========================================================================== #
# ==&gt; Все, что находится ниже, добавлено автором документа.

# ==&gt; Чтобы этот сценарий можно было использовать как "библиотеку", необходимо
# ==&gt; удалить все, что находится ниже и "source" этот файл в вашем сценарии.

# strcat
string0=one
string1=two
echo
echo "Проверка функции \"strcat\" :"
echo "Изначально \"string0\" = $string0"
echo "\"string1\" = $string1"
strcat string0 string1
echo "Теперь \"string0\" = $string0"
echo

# strlen
echo
echo "Проверка функции  \"strlen\" :"
str=123456789
echo "\"str\" = $str"
echo -n "Длина строки \"str\" = "
strlen str
echo



# Упражнение:
# ---------
# Добавьте проверку остальных функций.


exit 0
</pre>
        </div>

        <p>Michael Zick предоставил очень сложный пример работы с
        массивами и утилитой <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MD5SUMREF">md5sum</a>, используемой для кодирования
        сведений о каталоге.</p>

        <p>От переводчика:</p>

        <p>К своему стыду вынужден признаться, что перевод комментариев
        оказался мне не "по зубам", поэтому оставляю этот
        сценарий без перевода.</p>

        <div class="EXAMPLE">
          <a name="DIRECTORYINFO"></a>

          <p><strong>Пример A-21. Directory information</strong></p>
<pre class="PROGRAMLISTING">#! /bin/bash
# directory-info.sh
# Parses and lists directory information.

# NOTE: Change lines 273 and 353 per "README" file.

# Michael Zick is the author of this script.
# Used here with his permission.

# Controls
# If overridden by command arguments, they must be in the order:
#   Arg1: "Descriptor Directory"
#   Arg2: "Exclude Paths"
#   Arg3: "Exclude Directories"
#
# Environment Settings override Defaults.
# Command arguments override Environment Settings.

# Default location for content addressed file descriptors.
MD5UCFS=${1:-${MD5UCFS:-'/tmpfs/ucfs'}}

# Directory paths never to list or enter
declare -a \
  EXCLUDE_PATHS=${2:-${EXCLUDE_PATHS:-'(/proc /dev /devfs /tmpfs)'}}

# Directories never to list or enter
declare -a \
  EXCLUDE_DIRS=${3:-${EXCLUDE_DIRS:-'(ucfs lost+found tmp wtmp)'}}

# Files never to list or enter
declare -a \
  EXCLUDE_FILES=${3:-${EXCLUDE_FILES:-'(core "Name with Spaces")'}}


# Here document used as a comment block.
: &lt;&lt; LSfieldsDoc
# # # # # List Filesystem Directory Information # # # # #
#
#       ListDirectory "FileGlob" "Field-Array-Name"
# or
#       ListDirectory -of "FileGlob" "Field-Array-Filename"
#       '-of' meaning 'output to filename'
# # # # #

String format description based on: ls (GNU fileutils) version 4.0.36

Produces a line (or more) formatted:
inode permissions hard-links owner group ...
32736 -rw-------    1 mszick   mszick

size    day month date hh:mm:ss year path
2756608 Sun Apr 20 08:53:06 2003 /home/mszick/core

Unless it is formatted:
inode permissions hard-links owner group ...
266705 crw-rw----    1    root  uucp

major minor day month date hh:mm:ss year path
4,  68 Sun Apr 20 09:27:33 2003 /dev/ttyS4
NOTE: that pesky comma after the major number

NOTE: the 'path' may be multiple fields:
/home/mszick/core
/proc/982/fd/0 -&gt; /dev/null
/proc/982/fd/1 -&gt; /home/mszick/.xsession-errors
/proc/982/fd/13 -&gt; /tmp/tmpfZVVOCs (deleted)
/proc/982/fd/7 -&gt; /tmp/kde-mszick/ksycoca
/proc/982/fd/8 -&gt; socket:[11586]
/proc/982/fd/9 -&gt; pipe:[11588]

If that isn't enough to keep your parser guessing,
either or both of the path components may be relative:
../Built-Shared -&gt; Built-Static
../linux-2.4.20.tar.bz2 -&gt; ../../../SRCS/linux-2.4.20.tar.bz2

The first character of the 11 (10?) character permissions field:
's' Socket
'd' Directory
'b' Block device
'c' Character device
'l' Symbolic link
NOTE: Hard links not marked - test for identical inode numbers
on identical filesystems.
All information about hard linked files are shared, except
for the names and the name's location in the directory system.
NOTE: A "Hard link" is known as a "File Alias" on some systems.
'-' An undistingushed file

Followed by three groups of letters for: User, Group, Others
Character 1: '-' Not readable; 'r' Readable
Character 2: '-' Not writable; 'w' Writable
Character 3, User and Group: Combined execute and special
'-' Not Executable, Not Special
'x' Executable, Not Special
's' Executable, Special
'S' Not Executable, Special
Character 3, Others: Combined execute and sticky (tacky?)
'-' Not Executable, Not Tacky
'x' Executable, Not Tacky
't' Executable, Tacky
'T' Not Executable, Tacky

Followed by an access indicator
Haven't tested this one, it may be the eleventh character
or it may generate another field
' ' No alternate access
'+' Alternate access
LSfieldsDoc


ListDirectory()
{
        local -a T
        local -i of=0           # Default return in variable
#       OLD_IFS=$IFS            # Using BASH default ' \t\n'

        case "$#" in
        3)      case "$1" in
                -of)    of=1 ; shift ;;
                 * )    return 1 ;;
                esac ;;
        2)      : ;;            # Poor man's "continue"
        *)      return 1 ;;
        esac

        # NOTE: the (ls) command is NOT quoted (")
        T=( $(ls --inode --ignore-backups --almost-all --directory \
        --full-time --color=none --time=status --sort=none \
        --format=long $1) )

        case $of in
        # Assign T back to the array whose name was passed as $2
                0) eval $2=\( \"\$\{T\[@\]\}\" \) ;;
        # Write T into filename passed as $2
                1) echo "${T[@]}" &gt; "$2" ;;
        esac
        return 0
   }

# # # # # Is that string a legal number? # # # # #
#
#       IsNumber "Var"
# # # # # There has to be a better way, sigh...

IsNumber()
{
        local -i int
        if [ $# -eq 0 ]
        then
                return 1
        else
                (let int=$1)  2&gt;/dev/null
                return $?       # Exit status of the let thread
        fi
}

# # # # # Index Filesystem Directory Information # # # # #
#
#       IndexList "Field-Array-Name" "Index-Array-Name"
# or
#       IndexList -if Field-Array-Filename Index-Array-Name
#       IndexList -of Field-Array-Name Index-Array-Filename
#       IndexList -if -of Field-Array-Filename Index-Array-Filename
# # # # #

: &lt;&lt; IndexListDoc
Walk an array of directory fields produced by ListDirectory

Having suppressed the line breaks in an otherwise line oriented
report, build an index to the array element which starts each line.

Each line gets two index entries, the first element of each line
(inode) and the element that holds the pathname of the file.

The first index entry pair (Line-Number==0) are informational:
Index-Array-Name[0] : Number of "Lines" indexed
Index-Array-Name[1] : "Current Line" pointer into Index-Array-Name

The following index pairs (if any) hold element indexes into
the Field-Array-Name per:
Index-Array-Name[Line-Number * 2] : The "inode" field element.
NOTE: This distance may be either +11 or +12 elements.
Index-Array-Name[(Line-Number * 2) + 1] : The "pathname" element.
NOTE: This distance may be a variable number of elements.
Next line index pair for Line-Number+1.
IndexListDoc



IndexList()
{
        local -a LIST                   # Local of listname passed
        local -a -i INDEX=( 0 0 )       # Local of index to return
        local -i Lidx Lcnt
        local -i if=0 of=0              # Default to variable names

        case "$#" in                    # Simplistic option testing
                0) return 1 ;;
                1) return 1 ;;
                2) : ;;                 # Poor man's continue
                3) case "$1" in
                        -if) if=1 ;;
                        -of) of=1 ;;
                         * ) return 1 ;;
                   esac ; shift ;;
                4) if=1 ; of=1 ; shift ; shift ;;
                *) return 1
        esac

        # Make local copy of list
        case "$if" in
                0) eval LIST=\( \"\$\{$1\[@\]\}\" \) ;;
                1) LIST=( $(cat $1) ) ;;
        esac

        # Grok (grope?) the array
        Lcnt=${#LIST[@]}
        Lidx=0
        until (( Lidx &gt;= Lcnt ))
        do
        if IsNumber ${LIST[$Lidx]}
        then
                local -i inode name
                local ft
                inode=Lidx
                local m=${LIST[$Lidx+2]}        # Hard Links field
                ft=${LIST[$Lidx+1]:0:1}         # Fast-Stat
                case $ft in
                b)      ((Lidx+=12)) ;;         # Block device
                c)      ((Lidx+=12)) ;;         # Character device
                *)      ((Lidx+=11)) ;;         # Anything else
                esac
                name=Lidx
                case $ft in
                -)      ((Lidx+=1)) ;;          # The easy one
                b)      ((Lidx+=1)) ;;          # Block device
                c)      ((Lidx+=1)) ;;          # Character device
                d)      ((Lidx+=1)) ;;          # The other easy one
                l)      ((Lidx+=3)) ;;          # At LEAST two more fields
#  A little more elegance here would handle pipes,
#+ sockets, deleted files - later.
                *)      until IsNumber ${LIST[$Lidx]} || ((Lidx &gt;= Lcnt))
                        do
                                ((Lidx+=1))
                        done
                        ;;                      # Not required
                esac
                INDEX[${#INDEX[*]}]=$inode
                INDEX[${#INDEX[*]}]=$name
                INDEX[0]=${INDEX[0]}+1          # One more "line" found
# echo "Line: ${INDEX[0]} Type: $ft Links: $m Inode: \
# ${LIST[$inode]} Name: ${LIST[$name]}"

        else
                ((Lidx+=1))
        fi
        done
        case "$of" in
                0) eval $2=\( \"\$\{INDEX\[@\]\}\" \) ;;
                1) echo "${INDEX[@]}" &gt; "$2" ;;
        esac
        return 0                                # What could go wrong?
}

# # # # # Content Identify File # # # # #
#
#       DigestFile Input-Array-Name Digest-Array-Name
# or
#       DigestFile -if Input-FileName Digest-Array-Name
# # # # #

# Here document used as a comment block.
: &lt;&lt;DigestFilesDoc

The key (no pun intended) to a Unified Content File System (UCFS)
is to distinguish the files in the system based on their content.
Distinguishing files by their name is just, so, 20th Century.

The content is distinguished by computing a checksum of that content.
This version uses the md5sum program to generate a 128 bit checksum
representative of the file's contents.
There is a chance that two files having different content might
generate the same checksum using md5sum (or any checksum).  Should
that become a problem, then the use of md5sum can be replace by a
cyrptographic signature.  But until then...

The md5sum program is documented as outputting three fields (and it
does), but when read it appears as two fields (array elements).  This
is caused by the lack of whitespace between the second and third field.
So this function gropes the md5sum output and returns:
        [0]     32 character checksum in hexidecimal (UCFS filename)
        [1]     Single character: ' ' text file, '*' binary file
        [2]     Filesystem (20th Century Style) name
        Note: That name may be the character '-' indicating STDIN read.

DigestFilesDoc



DigestFile()
{
        local if=0              # Default, variable name
        local -a T1 T2

        case "$#" in
        3)      case "$1" in
                -if)    if=1 ; shift ;;
                 * )    return 1 ;;
                esac ;;
        2)      : ;;            # Poor man's "continue"
        *)      return 1 ;;
        esac

        case $if in
        0) eval T1=\( \"\$\{$1\[@\]\}\" \)
           T2=( $(echo ${T1[@]} | md5sum -) )
           ;;
        1) T2=( $(md5sum $1) )
           ;;
        esac

        case ${#T2[@]} in
        0) return 1 ;;
        1) return 1 ;;
        2) case ${T2[1]:0:1} in         # SanScrit-2.0.5
           \*) T2[${#T2[@]}]=${T2[1]:1}
               T2[1]=\*
               ;;
            *) T2[${#T2[@]}]=${T2[1]}
               T2[1]=" "
               ;;
           esac
           ;;
        3) : ;; # Assume it worked
        *) return 1 ;;
        esac

        local -i len=${#T2[0]}
        if [ $len -ne 32 ] ; then return 1 ; fi
        eval $2=\( \"\$\{T2\[@\]\}\" \)
}

# # # # # Locate File # # # # #
#
#       LocateFile [-l] FileName Location-Array-Name
# or
#       LocateFile [-l] -of FileName Location-Array-FileName
# # # # #

# A file location is Filesystem-id and inode-number

# Here document used as a comment block.
: &lt;&lt;StatFieldsDoc
        Based on stat, version 2.2
        stat -t and stat -lt fields
        [0]     name
        [1]     Total size
                File - number of bytes
                Symbolic link - string length of pathname
        [2]     Number of (512 byte) blocks allocated
        [3]     File type and Access rights (hex)
        [4]     User ID of owner
        [5]     Group ID of owner
        [6]     Device number
        [7]     Inode number
        [8]     Number of hard links
        [9]     Device type (if inode device) Major
        [10]    Device type (if inode device) Minor
        [11]    Time of last access
                May be disabled in 'mount' with noatime
                atime of files changed by exec, read, pipe, utime, mknod (mmap?)
                atime of directories changed by addition/deletion of files
        [12]    Time of last modification
                mtime of files changed by write, truncate, utime, mknod
                mtime of directories changed by addtition/deletion of files
        [13]    Time of last change
                ctime reflects time of changed inode information (owner, group
                permissions, link count
-*-*- Per:
        Return code: 0
        Size of array: 14
        Contents of array
        Element 0: /home/mszick
        Element 1: 4096
        Element 2: 8
        Element 3: 41e8
        Element 4: 500
        Element 5: 500
        Element 6: 303
        Element 7: 32385
        Element 8: 22
        Element 9: 0
        Element 10: 0
        Element 11: 1051221030
        Element 12: 1051214068
        Element 13: 1051214068

        For a link in the form of linkname -&gt; realname
        stat -t  linkname returns the linkname (link) information
        stat -lt linkname returns the realname information

        stat -tf and stat -ltf fields
        [0]     name
        [1]     ID-0?           # Maybe someday, but Linux stat structure
        [2]     ID-0?           # does not have either LABEL nor UUID
                                # fields, currently information must come
                                # from file-system specific utilities
        These will be munged into:
        [1]     UUID if possible
        [2]     Volume Label if possible
        Note: 'mount -l' does return the label and could return the UUID

        [3]     Maximum length of filenames
        [4]     Filesystem type
        [5]     Total blocks in the filesystem
        [6]     Free blocks
        [7]     Free blocks for non-root user(s)
        [8]     Block size of the filesystem
        [9]     Total inodes
        [10]    Free inodes

-*-*- Per:
        Return code: 0
        Size of array: 11
        Contents of array
        Element 0: /home/mszick
        Element 1: 0
        Element 2: 0
        Element 3: 255
        Element 4: ef53
        Element 5: 2581445
        Element 6: 2277180
        Element 7: 2146050
        Element 8: 4096
        Element 9: 1311552
        Element 10: 1276425

StatFieldsDoc


#       LocateFile [-l] FileName Location-Array-Name
#       LocateFile [-l] -of FileName Location-Array-FileName

LocateFile()
{
        local -a LOC LOC1 LOC2
        local lk="" of=0

        case "$#" in
        0) return 1 ;;
        1) return 1 ;;
        2) : ;;
        *) while (( "$#" &gt; 2 ))
           do
              case "$1" in
               -l) lk=-1 ;;
              -of) of=1 ;;
                *) return 1 ;;
              esac
           shift
           done ;;
        esac

# More Sanscrit-2.0.5
      # LOC1=( $(stat -t $lk $1) )
      # LOC2=( $(stat -tf $lk $1) )
      # Uncomment above two lines if system has "stat" command installed.
        LOC=( ${LOC1[@]:0:1} ${LOC1[@]:3:11}
              ${LOC2[@]:1:2} ${LOC2[@]:4:1} )

        case "$of" in
                0) eval $2=\( \"\$\{LOC\[@\]\}\" \) ;;
                1) echo "${LOC[@]}" &gt; "$2" ;;
        esac
        return 0
# Which yields (if you are lucky, and have "stat" installed)
# -*-*- Location Discriptor -*-*-
#       Return code: 0
#       Size of array: 15
#       Contents of array
#       Element 0: /home/mszick         20th Century name
#       Element 1: 41e8                 Type and Permissions
#       Element 2: 500                  User
#       Element 3: 500                  Group
#       Element 4: 303                  Device
#       Element 5: 32385                inode
#       Element 6: 22                   Link count
#       Element 7: 0                    Device Major
#       Element 8: 0                    Device Minor
#       Element 9: 1051224608           Last Access
#       Element 10: 1051214068          Last Modify
#       Element 11: 1051214068          Last Status
#       Element 12: 0                   UUID (to be)
#       Element 13: 0                   Volume Label (to be)
#       Element 14: ef53                Filesystem type
}



# And then there was some test code

ListArray() # ListArray Name
{
        local -a Ta

        eval Ta=\( \"\$\{$1\[@\]\}\" \)
        echo
        echo "-*-*- List of Array -*-*-"
        echo "Size of array $1: ${#Ta[*]}"
        echo "Contents of array $1:"
        for (( i=0 ; i&lt;${#Ta[*]} ; i++ ))
        do
            echo -e "\tElement $i: ${Ta[$i]}"
        done
        return 0
}

declare -a CUR_DIR
# For small arrays
ListDirectory "${PWD}" CUR_DIR
ListArray CUR_DIR

declare -a DIR_DIG
DigestFile CUR_DIR DIR_DIG
echo "The new \"name\" (checksum) for ${CUR_DIR[9]} is ${DIR_DIG[0]}"

declare -a DIR_ENT
# BIG_DIR # For really big arrays - use a temporary file in ramdisk
# BIG-DIR # ListDirectory -of "${CUR_DIR[11]}/*" "/tmpfs/junk2"
ListDirectory "${CUR_DIR[11]}/*" DIR_ENT

declare -a DIR_IDX
# BIG-DIR # IndexList -if "/tmpfs/junk2" DIR_IDX
IndexList DIR_ENT DIR_IDX

declare -a IDX_DIG
# BIG-DIR # DIR_ENT=( $(cat /tmpfs/junk2) )
# BIG-DIR # DigestFile -if /tmpfs/junk2 IDX_DIG
DigestFile DIR_ENT IDX_DIG
# Small (should) be able to parallize IndexList &amp; DigestFile
# Large (should) be able to parallize IndexList &amp; DigestFile &amp; the assignment
echo "The \"name\" (checksum) for the contents of ${PWD} is ${IDX_DIG[0]}"

declare -a FILE_LOC
LocateFile ${PWD} FILE_LOC
ListArray FILE_LOC

exit 0
</pre>
        </div>

        <p>Stephane Chazelas демонстрирует возможность объектно
        ориентированного подхода к программированию в
        Bash-сценариях.</p>

        <div class="EXAMPLE">
          <a name="OBJORIENTED"></a>

          <p><strong>Пример A-22. Объектно ориентированная база
          данных</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# obj-oriented.sh: Объектно ориентрованный подход к программированию в сценариях.
# Автор: Stephane Chazelas.


person.new()        # Очень похоже на объявление класса в C++.
{
  local obj_name=$1 name=$2 firstname=$3 birthdate=$4

  eval "$obj_name.set_name() {
          eval \"$obj_name.get_name() {
                   echo \$1
                 }\"
        }"

  eval "$obj_name.set_firstname() {
          eval \"$obj_name.get_firstname() {
                   echo \$1
                 }\"
        }"

  eval "$obj_name.set_birthdate() {
          eval \"$obj_name.get_birthdate() {
            echo \$1
          }\"
          eval \"$obj_name.show_birthdate() {
            echo \$(date -d \"1/1/1970 0:0:\$1 GMT\")
          }\"
          eval \"$obj_name.get_age() {
            echo \$(( (\$(date +%s) - \$1) / 3600 / 24 / 365 ))
          }\"
        }"

  $obj_name.set_name $name
  $obj_name.set_firstname $firstname
  $obj_name.set_birthdate $birthdate
}

echo

person.new self Bozeman Bozo 101272413
# Создается экземпляр класса "person.new" (фактически -- вызов функции с аргументами).

self.get_firstname       #   Bozo
self.get_name            #   Bozeman
self.get_age             #   28
self.get_birthdate       #   101272413
self.show_birthdate      #   Sat Mar 17 20:13:33 MST 1973

echo

# typeset -f
# чтобы просмотреть перечень созданных функций.

exit 0
</pre>
        </div>
      </div>

      <div class="APPENDIX">
        <hr>

        <h1><a name="SEDAWK"></a>Приложение B. Маленький учебник по Sed и
        Awk</h1>

        <p><a name="SEDREF"></a></p>

        <p>В этом приложении содержится очень краткое описание приемов
        работы с утилитами обработки текста <strong class="COMMAND">sed</strong> и <strong class="COMMAND">awk</strong>. Здесь будут рассмотрены лишь
        несколько базовых команд, которых, в принципе, будет
        достаточно, чтобы научиться понимать простейшие конструкции sed
        и awk внутри сценариев на языке командной оболочки.</p>

        <p><strong class="COMMAND">sed</strong>: неинтерактивный редактор
        текстовых файлов</p>

        <p><strong class="COMMAND">awk</strong>: язык обработки шаблонов с
        C-подобным синтаксисом</p>

        <p>При всех своих различиях, эти две утилиты обладают похожим
        синтаксисом, они обе умеют работать с <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REGEXREF">регулярными выражениями</a>, обе,
        по-умолчанию, читают данные с устройства <code class="FILENAME">stdin</code> и обе выводят результат обработки
        на устройство <code class="FILENAME">stdout</code>. Обе являются утилитами
        UNIX-систем, и прекрасно могут взаимодействовать между собой.
        Вывод от одной может быть перенаправлен, по конвейеру, на вход
        другой. Их комбинирование придает сценариям, на языке командной
        оболочки, мощь и гибкость языка Perl.</p>

        <div class="NOTE">
          <table class="NOTE" width="100%" border="0">
            <tbody><tr>
              <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

              <td align="left" valign="top">
                <p>Одно важное отличие состоит в том, что в случае с
                sed, сценарий легко может передавать дополнительные
                аргументы этой утилите, в то время, как в случае с awk
                (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COLTOTALER">Пример 33-3</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COLTOTALER2">Пример 9-22</a>), это более
                сложная задача .</p>
              </td>
            </tr>
          </tbody></table>
        </div>

        <div class="SECT1">
          <hr>

          <h2 class="SECT1"><a name="AEN14605"></a>B.1. Sed</h2>

          <p>Sed -- это неинтерактивный строчный редактор. Он принимает
          текст либо с устройства <code class="FILENAME">stdin</code>, либо из текстового файла,
          выполняет некоторые операции над строками и затем выводит
          результат на устройство <code class="FILENAME">stdout</code> или в файл. Как правило, в
          сценариях, sed используется в конвейерной обработке данных,
          совместно с другими командами и утилитами.</p>

          <p>Sed определяет, по заданному <span class="emphasis"><em class="EMPHASIS">адресному пространству</em></span>, над
          какими строками следует выполнить операции. <a name="AEN14612" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN14612"><span class="footnote">[66]</span></a> Адресное пространство строк
          задается либо их порядковыми номерами, либо шаблоном.
          Например, команда <code class="REPLACEABLE"><em>3d</em></code> заставит sed удалить
          третью строку, а команда <code class="REPLACEABLE"><em>/windows/d</em></code> означает, что
          все строки, содержащие <span class="QUOTE">"windows"</span>, должны быть
          удалены.</p>

          <p>Из всего разнообразия операций, мы остановимся на трех,
          используемых наиболее часто. Это <strong class="COMMAND">p</strong> -- печать (на <code class="FILENAME">stdout</code>), <strong class="COMMAND">d</strong> -- удаление и <strong class="COMMAND">s</strong> -- замена.</p>

          <div class="TABLE">
            <a name="AEN14623"></a>

            <p><strong>Таблица B-1. Основные операции sed</strong></p>

            <table border="1" class="CALSTABLE">
              <thead>
                <tr>
                  <th align="left" valign="top">Операция</th>

                  <th align="left" valign="top">Название</th>

                  <th align="left" valign="top">Описание</th>
                </tr>
              </thead>

              <tbody>
                <tr>
                  <td align="left" valign="top"><code class="OPTION">[диапазон строк]/p</code></td>

                  <td align="left" valign="top">print</td>

                  <td align="left" valign="top">Печать [указанного диапазона
                  строк]</td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">[диапазон строк]/d</code></td>

                  <td align="left" valign="top">delete</td>

                  <td align="left" valign="top">Удалить [указанный диапазон строк]</td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">s/pattern1/pattern2/</code></td>

                  <td align="left" valign="top">substitute</td>

                  <td align="left" valign="top">Заменить первое встреченное
                  соответствие шаблону pattern1, в строке, на
                  pattern2</td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">[диапазон
                  строк]/s/pattern1/pattern2/</code></td>

                  <td align="left" valign="top">substitute</td>

                  <td align="left" valign="top">Заменить первое встреченное
                  соответствие шаблону pattern1, на pattern2, в
                  указанном <code class="REPLACEABLE"><em>диапазоне
                  строк</em></code></td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">[диапазон
                  строк]/y/pattern1/pattern2/</code></td>

                  <td align="left" valign="top">transform</td>

                  <td align="left" valign="top">заменить любые символы из шаблона
                  pattern1 на соответствующие символы из pattern2, в
                  указанном <code class="REPLACEABLE"><em>диапазоне строк</em></code>
                  (эквивалент команды <strong class="COMMAND">tr</strong>)</td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">g</code></td>

                  <td align="left" valign="top">global</td>

                  <td align="left" valign="top">Операция выполняется над <span class="emphasis"><em class="EMPHASIS">всеми</em></span> найденными
                  соответствиями внутри каждой из заданных строк</td>
                </tr>
              </tbody>
            </table>
          </div>

          <div class="NOTE">
            <table class="NOTE" width="100%" border="0">
              <tbody><tr>
                <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                <td align="left" valign="top">
                  <p>Без оператора <code class="OPTION">g</code> (<span class="emphasis"><em class="EMPHASIS">global</em></span>), операция
                  замены будет производиться только для первого
                  найденного совпадения, с заданным шаблоном, в каждой
                  строке.</p>
                </td>
              </tr>
            </tbody></table>
          </div>

          <p>В отдельных случаях, операции sed необходимо заключать в
          кавычки.</p>
<pre class="PROGRAMLISTING">sed -e '/^$/d' $filename
#  Ключ -e говорит о том, что далее следует строка, которая должна интерпретироваться
#+ как набор инструкций редактирования.
# (При передаче одной инструкции, ключ "-e" является необязательным.)
#  "Строгие" кавычки ('') предотвращают интерпретацию символов регулярного выражения,
#+ как специальных символов, командным интерпретатором.
#
# Действия производятся над строками, содержащимися в файле $filename.
</pre>
          <br>
          <br>

          <p>В отдельных случаях, команды редактирования не работают в
          одиночных кавычках.</p>
<pre class="PROGRAMLISTING">filename=file1.txt
pattern=BEGIN

  sed "/^$pattern/d" "$filename"  # Результат вполне предсказуем.
# sed '/^$pattern/d' "$filename"    дает иной результат.
#        В данном случае, в "строгих" кавычках (' ... '),
#+      не происходит подстановки значения переменной "$pattern".
</pre>
          <br>
          <br>

          <div class="NOTE">
            <table class="NOTE" width="100%" border="0">
              <tbody><tr>
                <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

                <td align="left" valign="top">
                  <p>Sed использует ключ <code class="OPTION">-e</code> для того, чтобы определить,
                  что следующая строка является инструкцией, или
                  набором инструкций, редактирования. Если инструкция
                  является единственной, то использование этого ключа
                  не является обязательным.</p>
                </td>
              </tr>
            </tbody></table>
          </div>
<pre class="PROGRAMLISTING">sed -n '/xzy/p' $filename
# Ключ -n заставляет sed вывести только те строки, которые совпадают с указанным шаблоном.
# В противном случае (без ключа -n), будут выведены все строки.
# Здесь, ключ -e не является обязательным, поскольку здесь стоит единственная команда.
</pre>
          <br>
          <br>

          <div class="TABLE">
            <a name="AEN14681"></a>

            <p><strong>Таблица B-2. Примеры операций в sed</strong></p>

            <table border="1" class="CALSTABLE">
              <thead>
                <tr>
                  <th align="left" valign="top">Операция</th>

                  <th align="left" valign="top">Описание</th>
                </tr>
              </thead>

              <tbody>
                <tr>
                  <td align="left" valign="top"><code class="OPTION">8d</code></td>

                  <td align="left" valign="top">Удалить 8-ю строку.</td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">/^$/d</code></td>

                  <td align="left" valign="top">Удалить все пустые строки.</td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">1,/^$/d</code></td>

                  <td align="left" valign="top">Удалить все строки до первой пустой
                  строки, включительно.</td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">/Jones/p</code></td>

                  <td align="left" valign="top">Вывести строки, содержащие <span class="QUOTE">"Jones"</span> (с ключом
                  <span class="TOKEN">-n</span>).</td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">s/Windows/Linux/</code></td>

                  <td align="left" valign="top">В каждой строке, заменить первое
                  встретившееся слово <span class="QUOTE">"Windows"</span> на слово
                  <span class="QUOTE">"Linux"</span>.</td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">s/BSOD/stability/g</code></td>

                  <td align="left" valign="top">В каждой строке, заменить все
                  встретившиеся слова <span class="QUOTE">"BSOD"</span> на <span class="QUOTE">"stability"</span>.</td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">s/ *$//</code></td>

                  <td align="left" valign="top">Удалить все пробелы в конце каждой
                  строки.</td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">s/00*/0/g</code></td>

                  <td align="left" valign="top">Заменить все последовательности ведущих
                  нулей одним символом "0".</td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">/GUI/d</code></td>

                  <td align="left" valign="top">Удалить все строки, содержащие <span class="QUOTE">"GUI"</span>.</td>
                </tr>

                <tr>
                  <td align="left" valign="top"><code class="OPTION">s/GUI//g</code></td>

                  <td align="left" valign="top">Удалить все найденные <span class="QUOTE">"GUI"</span>, оставляя
                  остальную часть строки без изменений.</td>
                </tr>
              </tbody>
            </table>
          </div>

          <p>Замена строки пустой строкой, эквивалентна удалению части
          строки, совпадающей с шаблоном. Остальная часть строки
          остается без изменений. Например, <code class="USERINPUT"><strong>s/GUI//</strong></code>, изменит
          следующую строку</p>
<pre class="SCREEN"><code class="USERINPUT"><strong>The most important parts of any application are its GUI and sound effects</strong></code>
</pre>
          на 
<pre class="SCREEN"><code class="COMPUTEROUTPUT">The most important parts of any application are its  and sound effects</code>
</pre>
          <br>
          <br>

          <p>Символ обратного слэша представляет символ перевода
          строки, как символ замены. В этом случае, замещающее
          выражение продолжается на следующей строке.</p>
<pre class="PROGRAMLISTING">s/^  */\
/g
</pre>
          Эта инструкция заменит начальные пробелы в строке на символ
          перевода строки. Ожидаемый результат -- замена отступов в
          начале параграфа пустыми строками.<br>
          <br>

          <p>Указание диапазона строк, предшествующее одной, или более,
          инструкции может потребовать заключения инструкций в фигурные
          скобки, с соответствующими символами перевода строки.</p>
<pre class="PROGRAMLISTING">/[0-9A-Za-z]/,/^$/{
/^$/d
}
</pre>
          В этом случае будут удалены только первые из нескольких,
          идущих подряд, пустых строк. Это может использоваться для
          установки однострочных интервалов в файле, оставляя, при
          этом, пустые строки между параграфами.<br>
          <br>

          <div class="TIP">
            <table class="TIP" width="100%" border="0">
              <tbody><tr>
                <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/tip.gif" hspace="5" alt="Tip"></td>

                <td align="left" valign="top">
                  <p>Быстрый способ установки двойных межстрочных
                  интервалов в текстовых файлах -- <code class="USERINPUT"><strong>sed G
                  filename</strong></code>.</p>
                </td>
              </tr>
            </tbody></table>
          </div>

          <p>Примеры использования sed в сценариях командной оболочки,
          вы найдете в:</p>

          <ol type="1">
            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX3">Пример 33-1</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX4">Пример 33-2</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX57">Пример 12-2</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RN">Пример A-3</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GRP">Пример 12-12</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COL">Пример 12-20</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BEHEAD">Пример A-13</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TREE">Пример A-19</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#STRIPC">Пример 12-24</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FINDSTRING">Пример 10-9</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BASE">Пример 12-33</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MAILFORMAT">Пример A-2</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#RND">Пример 12-10</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WF">Пример 12-8</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LIFESLOW">Пример A-11</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SELFDOCUMENT">Пример 17-11</a></p>
            </li>
          </ol>
          <br>
          <br>

          <p>Ссылки на дополнительные сведения о sed, вы найдете в
          разделе <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BIBLIO"><em>Литература</em></a>.</p>
        </div>

        <div class="SECT1">
          <hr>

          <h2 class="SECT1"><a name="AWK"></a>B.2. Awk</h2>

          <p><a name="AWKREF"></a></p>

          <p><strong class="COMMAND">Awk</strong> -- это полноценный язык
          обработки текстовой информации с синтаксисом, напоминающим
          синтаксис языка <strong class="COMMAND">C</strong>. Он обладает довольно широким
          набором возможностей, однако, мы рассмотрим лишь некоторые из
          них -- наиболее употребимые в сценариях командной
          оболочки.</p>

          <p>Awk "разбивает" каждую строку на отдельные <span class="emphasis"><em class="EMPHASIS">поля</em></span>. По-умолчанию, поля -- это
          последовательности символов, отделенные друг от друга <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WHITESPACEREF">пробелами</a>, однако имеется
          возможность назначения других символов, в качестве
          разделителя полей. Awk анализирует и обрабатывает каждое поле
          в отдельности. Это делает его идеальным инструментом для
          работы со структурированными текстовыми файлами, осбенно с
          таблицами.</p>

          <p>Внутри сценариев командной оболочки, код awk, заключается
          в "строгие" (одиночные) кавычки и фигурные
          скобки.</p>
<pre class="PROGRAMLISTING">awk '{print $3}' $filename
# Выводит содержимое 3-го поля из файла $filename на устройство stdout.

awk '{print $1 $5 $6}' $filename
# Выводит содержимое 1-го, 5-го и 6-го полей из файла $filename.
</pre>
          <br>
          <br>

          <p>Только что, мы рассмотрели действие команды <strong class="COMMAND">print</strong>. Еще, на чем мы остановимся
          -- это переменные. Awk работает с переменными подобно
          сценариям командной оболочки, но более гибко.</p>
<pre class="PROGRAMLISTING">{ total += ${column_number} }
</pre>
          Эта команда добавит содержимое переменной <span class="emphasis"><em class="EMPHASIS">column_number</em></span> к переменной
          <span class="QUOTE">"total"</span>. Чтобы, в завершение
          вывести <span class="QUOTE">"total"</span>, можно использовать
          команду <strong class="COMMAND">END</strong>, которая открывает блок кода,
          отрабатывающий после того, как будут обработаны все входные
          данные. 
<pre class="PROGRAMLISTING">END { print total }
</pre>
          <br>
          <br>

          <p>Команде <strong class="COMMAND">END</strong>, соответствует команда <strong class="COMMAND">BEGIN</strong>, которая открывает блок кода,
          отрабатывающий перед началом обработки входных данных.</p>

          <p>Примеры использования awk в сценариях командной оболочки,
          вы найдете в:</p>

          <ol type="1">
            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX44">Пример 11-10</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REDIR4">Пример 16-7</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#STRIPC">Пример 12-24</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COLTOTALER">Пример 33-3</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COLTOTALER2">Пример 9-22</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COLTOTALER3">Пример 11-16</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PIDID">Пример 27-1</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CONSTAT">Пример 27-2</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FILEINFO">Пример 10-3</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BLOTOUT">Пример 12-42</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SEEDINGRANDOM">Пример 9-26</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IDELETE">Пример 12-3</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SUBSTRINGEX">Пример 9-12</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SUMPRODUCT">Пример 33-11</a></p>
            </li>

            <li>
              <p><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#USERLIST">Пример 10-8</a></p>
            </li>
          </ol>
          <br>
          <br>

          <p>Это все, что я хотел рассказать об awk. Дополнительные
          ссылки на информацию об awk, вы найдете в разделе <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BIBLIO"><em>Литература</em></a>.</p>
        </div>
      </div>

      <div class="APPENDIX">
        <hr>

        <h1><a name="EXITCODES"></a>Приложение C. Коды завершения, имеющие
        предопределенный смысл</h1>

        <p><a name="EXITCODESREF"></a></p>

        <div class="TABLE">
          <a name="AEN14880"></a>

          <p><strong>Таблица C-1. <span class="QUOTE">"Зарезервированные"</span> коды
          завершения</strong></p>

          <table border="1" class="CALSTABLE">
            <thead>
              <tr>
                <th align="left" valign="top">Код завершения</th>

                <th align="left" valign="top">Смысл</th>

                <th align="left" valign="top">Пример</th>

                <th align="left" valign="top">Примечание</th>
              </tr>
            </thead>

            <tbody>
              <tr>
                <td align="left" valign="top"><code class="OPTION">1</code></td>

                <td align="left" valign="top">разнообразные ошибки</td>

                <td align="left" valign="top">let "var1 = 1/0"</td>

                <td align="left" valign="top">различные ошибки, такие как <span class="QUOTE">"деление на ноль"</span> и
                пр.</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">2</code></td>

                <td align="left" valign="top">согласно документации к Bash -- неверное
                использование встроенных команд</td>

                <td align="left" valign="top">&nbsp;</td>

                <td align="left" valign="top">Встречаются довольно редко, обычно код
                завершения возвращается равным 1</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">126</code></td>

                <td align="left" valign="top">вызываемая команда не может быть
                выполнена</td>

                <td align="left" valign="top">&nbsp;</td>

                <td align="left" valign="top">возникает из-за проблем с правами доступа
                или когда вызван на исполнение неисполняемый файл</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">127</code></td>

                <td align="left" valign="top"><span class="QUOTE">"команда не
                найдена"</span></td>

                <td align="left" valign="top">&nbsp;</td>

                <td align="left" valign="top">Проблема связана либо с переменной
                окружения <code class="VARNAME">$PATH</code>, либо с неверным написанием
                имени команды</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">128</code></td>

                <td align="left" valign="top">неверный аргумент команды <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXITCOMMANDREF">exit</a></td>

                <td align="left" valign="top">exit 3.14159</td>

                <td align="left" valign="top">команда <strong class="COMMAND">exit</strong> может принимать только
                целочисленные значения, в диапазоне 0 - 255</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">128+n</code></td>

                <td align="left" valign="top">фатальная ошибка по сигналу <span class="QUOTE">"n"</span></td>

                <td align="left" valign="top"><strong class="COMMAND">kill -9</strong> <code class="VARNAME">$PPID</code> сценария</td>

                <td align="left" valign="top"><code class="USERINPUT"><strong>$?</strong></code> вернет 137
                (128 + 9)</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">130</code></td>

                <td align="left" valign="top">завершение по Control-C</td>

                <td align="left" valign="top">&nbsp;</td>

                <td align="left" valign="top">Control-C -- это выход по сигналу 2, (130
                = 128 + 2, см. выше)</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">255*</code></td>

                <td align="left" valign="top">код завершения вне допустимого
                диапазона</td>

                <td align="left" valign="top">exit -1</td>

                <td align="left" valign="top"><strong class="COMMAND">exit</strong> может принимать только
                целочисленные значения, в диапазоне 0 - 255</td>
              </tr>
            </tbody>
          </table>
        </div>

        <p>Согласно этой таблице, коды завершения 1 - 2, 126 - 165 и
        255 <a name="AEN14950" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FTN.AEN14950"><span class="footnote">[67]</span></a> имеют предопределенное
        значение, поэтому вам следует избегать употребления этих кодов
        для своих нужд. Завершение сценария с кодом возврата <strong class="COMMAND">exit 127</strong>, может привести в
        замешательство при поиске ошибок в сценарии (действительно ли
        он означает ошибку <span class="QUOTE">"команда не найдена"</span>? Или это
        предусмотренный программистом код завершения?). В большинстве
        случаев, программисты вставляют <strong class="COMMAND">exit 1</strong>, в качестве реакции на ошибку.
        Так как код завершения <span class="RETURNVALUE">1</span> подразумевает целый
        "букет" ошибок, то в данном случае трудно говорить о
        какой либо двусмысленности, хотя и об информативности --
        тоже.</p>

        <p>Не раз предпринимались попытки систематизировать коды
        завершения (см. <code class="FILENAME">/usr/include/sysexits.h</code>), но эта
        систематизация предназначена для программистов, пишущих на
        языках C и C++. Автор документа предлагает ограничить коды
        завершения, определяемые пользователем, диапазоном 64 - 113 (и,
        само собой разумеется -- 0, для обозначения успешного
        завершения), в соответствии со стандартом C/C++. Это сделало бы
        поиск ошибок более простым.</p>

        <p>Все сценарии, прилагаемые к данному документу, приведены в
        соответствие с этим стандартом, за исключением случаев, когда
        существуют отменяющие обстоятельства, например в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TMDIN">Пример 9-2</a>.</p>

        <div class="NOTE">
          <table class="NOTE" width="100%" border="0">
            <tbody><tr>
              <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

              <td align="left" valign="top">
                <p>Обращение к переменной <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#XSTATVARREF">$?</a>, из командной строки, после
                завершения работы сценария, дает результат, в
                соответствии с таблицей, приведенной выше, но только
                для Bash или <span class="emphasis"><em class="EMPHASIS">sh</em></span>. Под управлением csh
                или <span class="emphasis"><em class="EMPHASIS">tcsh</em></span> значения могут в
                некоторых случаях отличаться.</p>
              </td>
            </tr>
          </tbody></table>
        </div>
      </div>

      <div class="APPENDIX">
        <hr>

        <h1><a name="IOREDIRINTRO"></a>Приложение D. Подробное введение в
        операции ввода-вывода и перенаправление ввода-вывода</h1>

        <p><span class="emphasis"><em class="EMPHASIS">написано Stephane Chazelas и дополнено
        автором документа</em></span></p>

        <p>Практически любая команда предполагает доступность 3-х <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FDREF">файловых дескрипторов</a>. Первый -- <span class="emphasis"><em class="EMPHASIS">0</em></span> (стандвртный ввод, <code class="FILENAME">stdin</code>), доступный для чтения. И два
        других -- <span class="emphasis"><em class="EMPHASIS">1</em></span> (<code class="FILENAME">stdout</code>) и <span class="emphasis"><em class="EMPHASIS">2</em></span> (<code class="FILENAME">stderr</code>), доступные для записи.</p>

        <p>Запись, типа <code class="USERINPUT"><strong>ls 2&gt;&amp;1</strong></code>,
        означает временное перенаправление вывода, с устройства <code class="FILENAME">stderr</code> на устройство <code class="FILENAME">stdout</code>.</p>

        <p>В соответствии с соглашениями, команды принимают ввод из
        файла с дескриптором 0 (<code class="FILENAME">stdin</code>), выводят результат работы в файл
        с дескриптором 1 (<code class="FILENAME">stdout</code>), а сообщения об ошибках -- в
        файл с дескриптором 2 (<code class="FILENAME">stderr</code>). Если какой либо из этих трех
        дескрипторов окажется закрытым, то могут возникнуть
        определенные проблемы:</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>cat /etc/passwd &gt;&amp;-</strong></code>
<code class="COMPUTEROUTPUT">cat: standard output: Bad file descriptor</code>
     
</pre>

        <p>К примеру, когда пользователь запускает <strong class="COMMAND">xterm</strong>, то он сначала выполняет
        процедуру инициализации, а затем, перед запуском командной
        оболочки, <strong class="COMMAND">xterm</strong> трижды открывает терминальные
        устройства (/dev/pts/&lt;n&gt;, или нечто подобное).</p>

        <p>После этого, командная оболочка наследует эти три
        дескриптора, и любая команда, запускаемая в этой оболочке, так
        же наследует их. Термин <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IOREDIRREF">перенаправление</a> -- означает
        переназначение одного файлового дескриптора на другой (канал
        (конвейер) или что-то другое). Переназначение может быть
        выполнено локально (для отдельной команды, для группы команд,
        для подоболочки, для операторов <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REDIRREF">while, if, case, for</a>...) или глобально (с
        помощью <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXECREF">exec</a>).</p>

        <p><code class="USERINPUT"><strong>ls &gt; /dev/null</strong></code> --
        означает запуск команды <strong class="COMMAND">ls</strong> с файловым дескриптором 1,
        присоединенным к устройству <code class="FILENAME">/dev/null</code>.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>lsof -a -p $$ -d0,1,2</strong></code>
<code class="COMPUTEROUTPUT">COMMAND PID     USER   FD   TYPE DEVICE SIZE NODE NAME
 bash    363 bozo        0u   CHR  136,1         3 /dev/pts/1
 bash    363 bozo        1u   CHR  136,1         3 /dev/pts/1
 bash    363 bozo        2u   CHR  136,1         3 /dev/pts/1</code>


<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>exec 2&gt; /dev/null</strong></code>
<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>lsof -a -p $$ -d0,1,2</strong></code>
<code class="COMPUTEROUTPUT">COMMAND PID     USER   FD   TYPE DEVICE SIZE NODE NAME
 bash    371 bozo        0u   CHR  136,1         3 /dev/pts/1
 bash    371 bozo        1u   CHR  136,1         3 /dev/pts/1
 bash    371 bozo        2w   CHR    1,3       120 /dev/null</code>


<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>bash -c 'lsof -a -p $$ -d0,1,2' | cat</strong></code>
<code class="COMPUTEROUTPUT">COMMAND PID USER   FD   TYPE DEVICE SIZE NODE NAME
 lsof    379 root    0u   CHR  136,1         3 /dev/pts/1
 lsof    379 root    1w  FIFO    0,0      7118 pipe
 lsof    379 root    2u   CHR  136,1         3 /dev/pts/1</code>


<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo "$(bash -c 'lsof -a -p $$ -d0,1,2' 2&gt;&amp;1)"</strong></code>
<code class="COMPUTEROUTPUT">COMMAND PID USER   FD   TYPE DEVICE SIZE NODE NAME
 lsof    426 root    0u   CHR  136,1         3 /dev/pts/1
 lsof    426 root    1w  FIFO    0,0      7520 pipe
 lsof    426 root    2w  FIFO    0,0      7520 pipe</code>
</pre>
        <br>
        <br>

        <p><code class="USERINPUT"><strong>Упражнение:</strong></code>
        Проанализируйте следующий сценарий.</p>
<pre class="PROGRAMLISTING">#! /usr/bin/env bash

mkfifo /tmp/fifo1 /tmp/fifo2
while read a; do echo "FIFO1: $a"; done &lt; /tmp/fifo1 &amp;
exec 7&gt; /tmp/fifo1
exec 8&gt; &gt;(while read a; do echo "FD8: $a, to fd7"; done &gt;&amp;7)

exec 3&gt;&amp;1
(
 (
  (
   while read a; do echo "FIFO2: $a"; done &lt; /tmp/fifo2 | tee /dev/stderr | tee /dev/fd/4 | tee /dev/fd/5 | tee /dev/fd/6 &gt;&amp;7 &amp;
   exec 3&gt; /tmp/fifo2

   echo 1st, to stdout
   sleep 1
   echo 2nd, to stderr &gt;&amp;2
   sleep 1
   echo 3rd, to fd 3 &gt;&amp;3
   sleep 1
   echo 4th, to fd 4 &gt;&amp;4
   sleep 1
   echo 5th, to fd 5 &gt;&amp;5
   sleep 1                                                                                              
   echo 6th, through a pipe | sed 's/.*/PIPE: &amp;, to fd 5/' &gt;&amp;5                                          
   sleep 1                                                                                              
   echo 7th, to fd 6 &gt;&amp;6                                                                                
   sleep 1                                                                                              
   echo 8th, to fd 7 &gt;&amp;7
   sleep 1                                                                                              
   echo 9th, to fd 8 &gt;&amp;8                                                                                
                                                                                                        
  ) 4&gt;&amp;1 &gt;&amp;3 3&gt;&amp;- | while read a; do echo "FD4: $a"; done 1&gt;&amp;3 5&gt;&amp;- 6&gt;&amp;-                                
 ) 5&gt;&amp;1 &gt;&amp;3 | while read a; do echo "FD5: $a"; done 1&gt;&amp;3 6&gt;&amp;-
) 6&gt;&amp;1 &gt;&amp;3 | while read a; do echo "FD6: $a"; done 3&gt;&amp;-                                                 
                                                                                                        
rm -f /tmp/fifo1 /tmp/fifo2


# Выясните, куда переназначены файловые дескрипторы каждой команды и подоболочки.

exit 0
</pre>
        <br>
        <br>
      </div>

      <div class="APPENDIX">
        <hr>

        <h1><a name="LOCALIZATION"></a>Приложение E. Локализация</h1>

        <p>Возможность локализации сценариев Bash нигде в документации
        не описана.</p>

        <p>Локализованные сценарии выводят текст на том языке, который
        используется системой, в соответствии с настройками.
        Пользователь Linux, живущий в Берлине (Германия), будет видеть
        сообщения на немецком языке, в то время как другой
        пользователь, проживающий в Берлине штата Мэриленд (США) -- на
        английском.</p>

        <p>Для создания локализованых сценариев можно использовать
        следующий шаблон, предусматривающий вывод всех сообщений на
        языке пользователя (сообщения об ошибках, приглашения к вводу и
        т.п.).</p>
<pre class="PROGRAMLISTING">#!/bin/bash
# localized.sh

E_CDERROR=65

error()
{
  printf "$@" &gt;&amp;2
  exit $E_CDERROR
}

cd $var || error $"Can't cd to %s." "$var"
read -p $"Enter the value: " var
# ...
</pre>
        <br>
        <br>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>bash -D localized.sh</strong></code>
<code class="COMPUTEROUTPUT">"Can't cd to %s."
"Enter the value: "</code>
</pre>
        Это список всех текстовых сообщений, которые подлежат
        локализации. (Ключ <code class="OPTION">-D</code> выводит список строк в двойных
        кавычках, которым предшествует символ <span class="TOKEN">$</span>, без запуска сценария на
        исполнение.)<br>
        <br>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>bash --dump-po-strings localized.sh</strong></code>
<code class="COMPUTEROUTPUT">#: a:6
 msgid "Can't cd to %s."
 msgstr ""
 #: a:7
 msgid "Enter the value: "
 msgstr ""</code>
</pre>
        Ключ <code class="OPTION">--dump-po-strings</code> в Bash напоминает ключ
        <code class="OPTION">-D</code>, но выводит строки в формате <span class="QUOTE">"po"</span>, с помощью утилиты <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GETTEXTREF">gettext</a>. <br>
        <br>

        <p>Теперь построим файл <code class="FILENAME">language.po</code>, для каждого языка, на
        которые предполагается перевести сообщения сценария.
        Например:</p>

        <p>Файл ru.po сделан переводчиком, в оригинальном документе
        локализация выполнена на примере французского языка</p>

        <p>ru.po:</p>
<pre class="PROGRAMLISTING">#: a:6
msgid "Can't cd to %s."
msgstr "Невозможно перейти в каталог %s."
#: a:7
msgid "Enter the value: "
msgstr "Введите число: "
</pre>
        <br>
        <br>

        <p>Затем запустите <strong class="COMMAND">msgfmt</strong>.</p>

        <p><code class="USERINPUT"><strong>msgfmt -o localized.sh.mo
        ru.po</strong></code></p>

        <p>Перепишите получившийся файл <code class="FILENAME">localized.sh.mo</code> в каталог <code class="FILENAME">/usr/share/locale/ru/LC_MESSAGES</code> и
        добавьте в начало сценария строки:</p>
<pre class="PROGRAMLISTING">TEXTDOMAINDIR=/usr/share/locale
TEXTDOMAIN=localized.sh
</pre>
        <br>
        <br>

        <p>Если система корректно настроена на русскую локаль, то
        пользователь, запустивший сценарий, будет видеть сообщения на
        русском языке.</p>

        <div class="NOTE">
          <table class="NOTE" width="100%" border="0">
            <tbody><tr>
              <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

              <td align="left" valign="top">
                <p>В старых версиях Bash или в других командных
                оболочках, потребуется воспользоваться услугами утилиты
                <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GETTEXTREF">gettext</a>, с ключом <code class="OPTION">-s</code>. В этом случае наш сценарий
                будет выглядеть так:</p>

                <p><a name="GETTEXTEXAMPLE"></a></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# localized.sh

E_CDERROR=65

error() {
  local format=$1
  shift
  printf "$(gettext -s "$format")" "$@" &gt;&amp;2
  exit $E_CDERROR
}
cd $var || error "Can't cd to %s." "$var"
read -p "$(gettext -s "Enter the value: ")" var
# ...
</pre>
                <br>
                <br>
              </td>
            </tr>
          </tbody></table>
        </div>

        <p>А переменные <code class="VARNAME">TEXTDOMAIN</code> и <code class="VARNAME">TEXTDOMAINDIR</code>, необходимо будет
        экспортировать в окружение.</p>

        <p>---</p>

        <p>Автор этого приложения: Stephane Chazelas.</p>
      </div>

      <div class="APPENDIX">
        <hr>

        <h1><a name="HISTCOMMANDS"></a>Приложение F. История команд</h1>

        <p>Командная оболочка Bash предоставляет в распоряжение
        пользователя инструментарий командной строки, позволяющий
        управлять <span class="emphasis"><em class="EMPHASIS">историей команд</em></span>. История команд
        -- это, прежде всего, очень удобный инструмент, сокращающий
        ручной ввод.</p>

        <p>История команд Bash:</p>

        <ol type="1">
          <li>
            <p><strong class="COMMAND">history</strong></p>
          </li>

          <li>
            <p><strong class="COMMAND">fc</strong></p>
          </li>
        </ol>
        <br>
        <br>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>history</strong></code>
<code class="COMPUTEROUTPUT">1  mount /mnt/cdrom
2  cd /mnt/cdrom
3  ls
     ...</code>
             
</pre>
        <br>
        <br>

        <p>Внутренние переменные Bash, связанные с историей команд:</p>

        <ol type="1">
          <li>
            <p>$HISTCMD</p>
          </li>

          <li>
            <p>$HISTCONTROL</p>
          </li>

          <li>
            <p>$HISTIGNORE</p>
          </li>

          <li>
            <p>$HISTFILE</p>
          </li>

          <li>
            <p>$HISTFILESIZE</p>
          </li>

          <li>
            <p>$HISTSIZE</p>
          </li>

          <li>
            <p>!!</p>
          </li>

          <li>
            <p>!$</p>
          </li>

          <li>
            <p>!#</p>
          </li>

          <li>
            <p>!N</p>
          </li>

          <li>
            <p>!-N</p>
          </li>

          <li>
            <p>!STRING</p>
          </li>

          <li>
            <p>!?STRING?</p>
          </li>

          <li>
            <p>^STRING^string^</p>
          </li>
        </ol>
        <br>
        <br>

        <p>К сожалению, инструменты истории команд, в Bash, совершенно
        бесполезны в сценариях.</p>
<pre class="PROGRAMLISTING">#!/bin/bash
# history.sh
# Попытка воспользоваться 'историей' команд в сценарии.

history

# На экран ничего не выводится.
# История команд не работает в сценариях.
</pre>
        <br>
        <br>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>./history.sh</strong></code>
<code class="COMPUTEROUTPUT">(ничего не выводится)</code>
             
</pre>
        <br>
        <br>
      </div>

      <div class="APPENDIX">
        <hr>

        <h1><a name="SAMPLE-BASHRC"></a>Приложение G. Пример файла <code class="FILENAME">.bashrc</code></h1>

        <p>Файл <code class="FILENAME">~/.bashrc</code> определяет поведение командной
        оболочки. Внимательное изучение этого примера поможет вам
        значительно продвинуться в понимании Bash.</p>

        <p><a href="mailto:emmanuel.rouat@wanadoo.fr" target="_top">Emmanuel Rouat</a> представил следующий, очень
        сложный, файл <code class="FILENAME">.bashrc</code>, написанный для операционной
        системы Linux. Предложения и замечания приветствуются.</p>

        <p>Внимательно изучите этот файл. Отдельные участки этого файла
        вы свободно можете использовать в своем собственном <code class="FILENAME">.bashrc</code> или, даже в своих сценариях!</p>

        <div class="EXAMPLE">
          <a name="BASHRC"></a>

          <p><strong>Пример G-1. Пример файла <code class="FILENAME">.bashrc</code></strong></p>
<pre class="PROGRAMLISTING">#===============================================================
#
# ЛИЧНЫЙ ФАЙЛ $HOME/.bashrc для bash-2.05a (или выше)
#
# Время последней модификации: Втр Апр 15 20:32:34 CEST 2003
#
# Этот файл содержит настройки интерактивной командной оболочки.
# Здесь размещены определения псевдонимов, функций
# и других элементов Bash, таких как prompt (приглашение к вводу).
#
# Изначально, этот файл был создан в операционной системе Solaris,
# но позднее был переделан под Redhat
# --&gt; Модифицирован под Linux.
# Большая часть кода, который находится здесь, была взята из
# Usenet (или Интернет).
# Этот файл содержит слишком много определений -- помните, это всего лишь пример.
#
#
#===============================================================

# --&gt; Комментарии, добавленные автором HOWTO.
# --&gt; И дополнены автором сценария Emmanuel Rouat :-)

#-----------------------------------
# Глобальные определения
#-----------------------------------

if [ -f /etc/bashrc ]; then
        . /etc/bashrc   # --&gt; Прочитать настройки из /etc/bashrc, если таковой имеется.
fi

#-------------------------------------------------------------
# Настройка переменной $DISPLAY (если еще не установлена)
# Это срабатывает под linux - в вашем случае все может быть по другому....
# Проблема в том, что различные типы терминалов
# дают разные ответы на запрос 'who am i'......
# я не нашел 'универсального' метода
#-------------------------------------------------------------

function get_xserver ()
{
    case $TERM in
        xterm )
            XSERVER=$(who am i | awk '{print $NF}' | tr -d ')''(' )
            XSERVER=${XSERVER%%:*}
            ;;
        aterm | rxvt)
        # добавьте здесь свой код.....
            ;;
    esac
}

if [ -z ${DISPLAY:=""} ]; then
    get_xserver
    if [[ -z ${XSERVER}  || ${XSERVER} == $(hostname) || ${XSERVER} == "unix" ]]; then
        DISPLAY=":0.0"          # для локального хоста
    else
        DISPLAY=${XSERVER}:0.0  # для удаленного хоста
    fi
fi

export DISPLAY

#---------------
# Некоторые настройки
#---------------

ulimit -S -c 0          # Запрет на создание файлов coredump
set -o notify
set -o noclobber
set -o ignoreeof
set -o nounset
#set -o xtrace          # полезно для отладки

# Разрешающие настройки:
shopt -s cdspell
shopt -s cdable_vars
shopt -s checkhash
shopt -s checkwinsize
shopt -s mailwarn
shopt -s sourcepath
shopt -s no_empty_cmd_completion  # только для bash&gt;=2.04
shopt -s cmdhist
shopt -s histappend histreedit histverify
shopt -s extglob

# Запрещающие настройки:
shopt -u mailwarn
unset MAILCHECK         # Я не желаю, чтобы командная оболочка сообщала мне о прибытии почты


export TIMEFORMAT=$'\nreal %3R\tuser %3U\tsys %3S\tpcpu %P\n'
export HISTIGNORE="&amp;:bg:fg:ll:h"
export HOSTFILE=$HOME/.hosts    # Поместить список удаленных хостов в файл ~/.hosts



#-----------------------
# Greeting, motd etc...
#-----------------------

# Для начала определить некоторые цвета:
red='\e[0;31m'
RED='\e[1;31m'
blue='\e[0;34m'
BLUE='\e[1;34m'
cyan='\e[0;36m'
CYAN='\e[1;36m'
NC='\e[0m'              # No Color (нет цвета)
# --&gt; Прекрасно. Имеет тот же эффект, что и "ansi.sys" в DOS.

# Лучше выглядит на черном фоне.....
echo -e "${CYAN}This is BASH ${RED}${BASH_VERSION%.*}${CYAN} - DISPLAY on ${RED}$DISPLAY${NC}\n"
date
if [ -x /usr/games/fortune ]; then
    /usr/games/fortune -s     # сделает наш день более интересным.... :-)
fi

function _exit()        # функция, запускающаяся при выходе из оболочки
{
    echo -e "${RED}Аста ла виста, бэби ${NC}"
}
trap _exit EXIT

#---------------
# Prompt
#---------------

if [[ "${DISPLAY#$HOST}" != ":0.0" &amp;&amp;  "${DISPLAY}" != ":0" ]]; then
    HILIT=${red}   # на удаленной системе: prompt будет частично красным
else
    HILIT=${cyan}  # на локальной системе: prompt будет частично циановым
fi

#  --&gt; Замените \W на \w в функциях ниже
#+ --&gt; чтобы видеть в оболочке полный путь к текущему каталогу.

function fastprompt()
{
    unset PROMPT_COMMAND
    case $TERM in
        *term | rxvt )
            PS1="${HILIT}[\h]$NC \W &gt; \[\033]0;\${TERM} [\u@\h] \w\007\]" ;;
        linux )
            PS1="${HILIT}[\h]$NC \W &gt; " ;;
        *)
            PS1="[\h] \W &gt; " ;;
    esac
}

function powerprompt()
{
    _powerprompt()
    {
        LOAD=$(uptime|sed -e "s/.*: \([^,]*\).*/\1/" -e "s/ //g")
    }

    PROMPT_COMMAND=_powerprompt
    case $TERM in
        *term | rxvt  )
            PS1="${HILIT}[\A \$LOAD]$NC\n[\h \#] \W &gt; \[\033]0;\${TERM} [\u@\h] \w\007\]" ;;
        linux )
            PS1="${HILIT}[\A - \$LOAD]$NC\n[\h \#] \w &gt; " ;;
        * )
            PS1="[\A - \$LOAD]\n[\h \#] \w &gt; " ;;
    esac
}

powerprompt     # это prompt по-умолчанию - может работать довольно медленно
                # Если это так, то используйте fastprompt....

#===============================================================
#
# ПСЕВДОНИМЫ И ФУНКЦИИ
#
# Возможно некоторые из функций, приведенных здесь, окажутся для вас слишком большими,
# но на моей рабочей станции установлено 512Mb ОЗУ, так что.....
# Если пожелаете уменьшить размер этого файла, то можете оформить эти функции
# в виде отдельных сценариев.
#
# Большинство функций были взяты, почти без переделки, из примеров
# к bash-2.04.
#
#===============================================================

#-------------------
# Псевдонимы
#-------------------

alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
# -&gt; Предотвращает случайное удаление файлов.
alias mkdir='mkdir -p'

alias h='history'
alias j='jobs -l'
alias r='rlogin'
alias which='type -all'
alias ..='cd ..'
alias path='echo -e ${PATH//:/\\n}'
alias print='/usr/bin/lp -o nobanner -d $LPDEST'   # Предполагается, что LPDEST определен
alias pjet='enscript -h -G -fCourier9 -d $LPDEST'  # Печать через enscript
alias background='xv -root -quit -max -rmode 5'    # Положить картинку в качестве фона
alias du='du -kh'
alias df='df -kTh'

# Различные варианты 'ls' (предполагается, что установлена GNU-версия ls)
alias la='ls -Al'               # показать скрытые файлы
alias ls='ls -hF --color'       # выделить различные типы файлов цветом
alias lx='ls -lXB'              # сортировка по расширению
alias lk='ls -lSr'              # сортировка по размеру
alias lc='ls -lcr'              # сортировка по времени изменения
alias lu='ls -lur'              # сортировка по времени последнего обращения
alias lr='ls -lR'               # рекурсивный обход подкаталогов
alias lt='ls -ltr'              # сортировка по дате
alias lm='ls -al |more'         # вывод через 'more'
alias tree='tree -Csu'          # альтернатива 'ls'

# подготовка 'less'
alias more='less'
export PAGER=less
export LESSCHARSET='latin1'
export LESSOPEN='|/usr/bin/lesspipe.sh %s 2&gt;&amp;-' # если существует lesspipe.sh
export LESS='-i -N -w  -z-4 -g -e -M -X -F -R -P%t?f%f \
:stdin .?pb%pb\%:?lbLine %lb:?bbByte %bb:-...'

# проверка правописания - настоятельно рекомендую :-)
alias xs='cd'
alias vf='cd'
alias moer='more'
alias moew='more'
alias kk='ll'

#----------------
# добавим немножко "приятностей"
#----------------

function xtitle ()
{
    case "$TERM" in
        *term | rxvt)
            echo -n -e "\033]0;$*\007" ;;
        *)
            ;;
    esac
}

# псевдонимы...
alias top='xtitle Processes on $HOST &amp;&amp; top'
alias make='xtitle Making $(basename $PWD) ; make'
alias ncftp="xtitle ncFTP ; ncftp"

# .. и функции
function man ()
{
    for i ; do
        xtitle The $(basename $1|tr -d .[:digit:]) manual
        command man -F -a "$i"
    done
}

function ll(){ ls -l "$@"| egrep "^d" ; ls -lXB "$@" 2&gt;&amp;-| egrep -v "^d|total "; }
function te()  # "обертка" вокруг xemacs/gnuserv
{
    if [ "$(gnuclient -batch -eval t 2&gt;&amp;-)" == "t" ]; then
        gnuclient -q "$@";
    else
        ( xemacs "$@" &amp;);
    fi
}

#-----------------------------------
# Функции для работы с файлами и строками:
#-----------------------------------

# Поиск файла по шаблону:
function ff() { find . -type f -iname '*'$*'*' -ls ; }
# Поиск файла по шаблону в $1 и запуск команды в $2 с ним:
function fe() { find . -type f -iname '*'$1'*' -exec "${2:-file}" {} \;  ; }
# поиск строки по файлам:
function fstr()
{
    OPTIND=1
    local case=""
    local usage="fstr: поиск строки в файлах.
Порядок использования: fstr [-i] \"шаблон\" [\"шаблон_имени_файла\"] "
    while getopts :it opt
    do
        case "$opt" in
        i) case="-i " ;;
        *) echo "$usage"; return;;
        esac
    done
    shift $(( $OPTIND - 1 ))
    if [ "$#" -lt 1 ]; then
        echo "$usage"
        return;
    fi
    local SMSO=$(tput smso)
    local RMSO=$(tput rmso)
    find . -type f -name "${2:-*}" -print0 | xargs -0 grep -sn ${case} "$1" 2&gt;&amp;- | \
sed "s/$1/${SMSO}\0${RMSO}/gI" | more
}

function cuttail() # удалить последние n строк в файле, по-умолчанию 10
{
    nlines=${2:-10}
    sed -n -e :a -e "1,${nlines}!{P;N;D;};N;ba" $1
}

function lowercase()  # перевести имя файла в нижний регистр
{
    for file ; do
        filename=${file##*/}
        case "$filename" in
        */*) dirname==${file%/*} ;;
        *) dirname=.;;
        esac
        nf=$(echo $filename | tr A-Z a-z)
        newname="${dirname}/${nf}"
        if [ "$nf" != "$filename" ]; then
            mv "$file" "$newname"
            echo "lowercase: $file --&gt; $newname"
        else
            echo "lowercase: имя файла $file не было изменено."
        fi
    done
}

function swap()         # меняет 2 файла местами
{
    local TMPFILE=tmp.$$
    mv "$1" $TMPFILE
    mv "$2" "$1"
    mv $TMPFILE "$2"
}


#-----------------------------------
# Функции для работы с процессами/системой:
#-----------------------------------

function my_ps() { ps $@ -u $USER -o pid,%cpu,%mem,bsdtime,command ; }
function pp() { my_ps f | awk '!/awk/ &amp;&amp; $0~var' var=${1:-".*"} ; }

# Эта функция является грубым аналогом 'killall' в linux
# но не эквивалентна (насколько я знаю) 'killall' в Solaris
function killps()   # "Прибить" процесс по его имени
{
    local pid pname sig="-TERM"   # сигнал, рассылаемый по-умолчанию
    if [ "$#" -lt 1 ] || [ "$#" -gt 2 ]; then
        echo "Порядок использования: killps [-SIGNAL] шаблон_имени_процесса"
        return;
    fi
    if [ $# = 2 ]; then sig=$1 ; fi
    for pid in $(my_ps| awk '!/awk/ &amp;&amp; $0~pat { print $1 }' pat=${!#} ) ; do
        pname=$(my_ps | awk '$1~var { print $5 }' var=$pid )
        if ask "Послать сигнал $sig процессу $pid &lt;$pname&gt;?"
            then kill $sig $pid
        fi
    done
}

function my_ip() # IP адрес
{
    MY_IP=$(/sbin/ifconfig ppp0 | awk '/inet/ { print $2 } ' | sed -e s/addr://)
    MY_ISP=$(/sbin/ifconfig ppp0 | awk '/P-t-P/ { print $3 } ' | sed -e s/P-t-P://)
}

function ii()   # Дополнительные сведения о системе
{
    echo -e "\nВы находитесь на ${RED}$HOST"
    echo -e "\nДополнительная информация:$NC " ; uname -a
    echo -e "\n${RED}В системе работают пользователи:$NC " ; w -h
    echo -e "\n${RED}Дата:$NC " ; date
    echo -e "\n${RED}Время, прошедшее с момента последней перезагрузки :$NC " ; uptime
    echo -e "\n${RED}Память :$NC " ; free
    my_ip 2&gt;&amp;- ;
    echo -e "\n${RED}IP адрес:$NC" ; echo ${MY_IP:-"Соединение не установлено"}
    echo -e "\n${RED}Адрес провайдера (ISP):$NC" ; echo ${MY_ISP:-"Соединение не установлено"}
    echo
}

# Разные утилиты:

function repeat()       # повторить команду n раз
{
    local i max
    max=$1; shift;
    for ((i=1; i &lt;= max ; i++)); do  # --&gt; C-подобный синтаксис
        eval "$@";
    done
}

function ask()
{
    echo -n "$@" '[y/n] ' ; read ans
    case "$ans" in
        y*|Y*) return 0 ;;
        *) return 1 ;;
    esac
}

#=========================================================================
#
# ПРОГРАММНЫЕ ДОПОЛНЕНИЯ - ТОЛЬКО НАЧИНАЯ С ВЕРСИИ BASH-2.04
# Большая часть дополнений взята из докуентации к bash 2.05  и из
# пакета 'Bash completion' (http://www.caliban.org/bash/index.shtml#completion)
# автор -- Ian McDonalds
# Фактически, у вас должен стоять bash-2.05a
#
#=========================================================================

if [ "${BASH_VERSION%.*}" \&lt; "2.05" ]; then
    echo "Вам необходимо обновиться до версии 2.05"
    return
fi

shopt -s extglob        # необходимо
set +o nounset          # иначе некоторые дополнения не будут работать

complete -A hostname   rsh rcp telnet rlogin r ftp ping disk
complete -A export     printenv
complete -A variable   export local readonly unset
complete -A enabled    builtin
complete -A alias      alias unalias
complete -A function   function
complete -A user       su mail finger

complete -A helptopic  help
complete -A shopt      shopt
complete -A stopped -P '%' bg
complete -A job -P '%'     fg jobs disown

complete -A directory  mkdir rmdir
complete -A directory   -o default cd

# Архивация
complete -f -o default -X '*.+(zip|ZIP)'  zip
complete -f -o default -X '!*.+(zip|ZIP)' unzip
complete -f -o default -X '*.+(z|Z)'      compress
complete -f -o default -X '!*.+(z|Z)'     uncompress
complete -f -o default -X '*.+(gz|GZ)'    gzip
complete -f -o default -X '!*.+(gz|GZ)'   gunzip
complete -f -o default -X '*.+(bz2|BZ2)'  bzip2
complete -f -o default -X '!*.+(bz2|BZ2)' bunzip2
# Postscript,pdf,dvi.....
complete -f -o default -X '!*.ps'  gs ghostview ps2pdf ps2ascii
complete -f -o default -X '!*.dvi' dvips dvipdf xdvi dviselect dvitype
complete -f -o default -X '!*.pdf' acroread pdf2ps
complete -f -o default -X '!*.+(pdf|ps)' gv
complete -f -o default -X '!*.texi*' makeinfo texi2dvi texi2html texi2pdf
complete -f -o default -X '!*.tex' tex latex slitex
complete -f -o default -X '!*.lyx' lyx
complete -f -o default -X '!*.+(htm*|HTM*)' lynx html2ps
# Multimedia
complete -f -o default -X '!*.+(jp*g|gif|xpm|png|bmp)' xv gimp
complete -f -o default -X '!*.+(mp3|MP3)' mpg123 mpg321
complete -f -o default -X '!*.+(ogg|OGG)' ogg123



complete -f -o default -X '!*.pl'  perl perl5

# Эти 'универсальные' дополнения работают тогда, когда команды вызываются
# с, так называемыми, 'длинными ключами', например: 'ls --all' вместо 'ls -a'

_get_longopts ()
{
    $1 --help | sed  -e '/--/!d' -e 's/.*--\([^[:space:].,]*\).*/--\1/'| \
grep ^"$2" |sort -u ;
}

_longopts_func ()
{
    case "${2:-*}" in
        -*)     ;;
        *)      return ;;
    esac

    case "$1" in
        \~*)    eval cmd="$1" ;;
        *)      cmd="$1" ;;
    esac
    COMPREPLY=( $(_get_longopts ${1} ${2} ) )
}
complete  -o default -F _longopts_func configure bash
complete  -o default -F _longopts_func wget id info a2ps ls recode


_make_targets ()
{
    local mdef makef gcmd cur prev i

    COMPREPLY=()
    cur=${COMP_WORDS[COMP_CWORD]}
    prev=${COMP_WORDS[COMP_CWORD-1]}

    # Если аргумент prev это -f, то вернуть возможные варианты имен файлов.
    # будем великодушны и вернем несколько вариантов
    # `makefile Makefile *.mk'
    case "$prev" in
        -*f)    COMPREPLY=( $(compgen -f $cur ) ); return 0;;
    esac

    # Если запрошены возможные ключи, то вернуть ключи posix
    case "$cur" in
        -)      COMPREPLY=(-e -f -i -k -n -p -q -r -S -s -t); return 0;;
    esac

    # попробовать передать make `makefile' перед тем как попробовать передать `Makefile'
    if [ -f makefile ]; then
        mdef=makefile
    elif [ -f Makefile ]; then
        mdef=Makefile
    else
        mdef=*.mk
    fi

    # прежде чем просмотреть "цели", убедиться, что имя makefile было задано
    # ключом -f
    for (( i=0; i &lt; ${#COMP_WORDS[@]}; i++ )); do
        if [[ ${COMP_WORDS[i]} == -*f ]]; then
            eval makef=${COMP_WORDS[i+1]}
            break
        fi
    done

        [ -z "$makef" ] &amp;&amp; makef=$mdef

    # Если задан шаблон поиска, то ограничиться
    # этим шаблоном
    if [ -n "$2" ]; then gcmd='grep "^$2"' ; else gcmd=cat ; fi

    # если мы не желаем использовать *.mk, то необходимо убрать cat и использовать
    # test -f $makef с перенаправлением ввода
    COMPREPLY=( $(cat $makef 2&gt;/dev/null | awk 'BEGIN {FS=":"} /^[^.#   ][^=]*:/ {print $1}' | tr -s ' ' '\012' | sort -u | eval $gcmd ) )
}

complete -F _make_targets -X '+($*|*.[cho])' make gmake pmake


# cvs(1) completion
_cvs ()
{
    local cur prev
    COMPREPLY=()
    cur=${COMP_WORDS[COMP_CWORD]}
    prev=${COMP_WORDS[COMP_CWORD-1]}

    if [ $COMP_CWORD -eq 1 ] || [ "${prev:0:1}" = "-" ]; then
        COMPREPLY=( $( compgen -W 'add admin checkout commit diff \
        export history import log rdiff release remove rtag status \
        tag update' $cur ))
    else
        COMPREPLY=( $( compgen -f $cur ))
    fi
    return 0
}
complete -F _cvs cvs

_killall ()
{
    local cur prev
    COMPREPLY=()
    cur=${COMP_WORDS[COMP_CWORD]}

    # получить список процессов
    COMPREPLY=( $( /usr/bin/ps -u $USER -o comm  | \
        sed -e '1,1d' -e 's#[]\[]##g' -e 's#^.*/##'| \
        awk '{if ($0 ~ /^'$cur'/) print $0}' ))

    return 0
}

complete -F _killall killall killps


# Функция обработки мета-команд
# В настоящее время недостаточно отказоустойчива (например, mount и umount
# обрабатываются некорректно), но все еще актуальна. Автор Ian McDonald, изменена мной.

_my_command()
{
    local cur func cline cspec

    COMPREPLY=()
    cur=${COMP_WORDS[COMP_CWORD]}

    if [ $COMP_CWORD = 1 ]; then
        COMPREPLY=( $( compgen -c $cur ) )
    elif complete -p ${COMP_WORDS[1]} &amp;&gt;/dev/null; then
        cspec=$( complete -p ${COMP_WORDS[1]} )
        if [ "${cspec%%-F *}" != "${cspec}" ]; then
            # complete -F &lt;function&gt;
            #
            # COMP_CWORD and COMP_WORDS() доступны на запись,
            # так что мы можем установить их перед тем,
            # как передать их дальше

            # уменьшить на 1 текущий номер лексемы
            COMP_CWORD=$(( $COMP_CWORD - 1 ))
            # получить имя функции
            func=${cspec#*-F }
            func=${func%% *}
            # получить командную строку, исключив первую команду
            cline="${COMP_LINE#$1 }"
            # разбить на лексемы и поместить в массив
                COMP_WORDS=( $cline )
            $func $cline
        elif [ "${cspec#*-[abcdefgjkvu]}" != "" ]; then
            # complete -[abcdefgjkvu]
            #func=$( echo $cspec | sed -e 's/^.*\(-[abcdefgjkvu]\).*$/\1/' )
            func=$( echo $cspec | sed -e 's/^complete//' -e 's/[^ ]*$//' )
            COMPREPLY=( $( eval compgen $func $cur ) )
        elif [ "${cspec#*-A}" != "$cspec" ]; then
            # complete -A &lt;type&gt;
            func=${cspec#*-A }
        func=${func%% *}
        COMPREPLY=( $( compgen -A $func $cur ) )
        fi
    else
        COMPREPLY=( $( compgen -f $cur ) )
    fi
}


complete -o default -F _my_command nohup exec eval trace truss strace sotruss gdb
complete -o default -F _my_command command type which man nice

# Локальные переменные:
# mode:shell-script
# sh-shell:bash
# Конец:
</pre>
        </div>
      </div>

      <div class="APPENDIX">
        <hr>

        <h1><a name="DOSBATCH"></a>Приложение H. Преобразование пакетных
        (*.bat) файлов DOS в сценарии командной оболочки</h1>

        <p><a name="DOSBATCH1"></a></p>

        <p>Большое число программистов начинало изучать скриптовые
        языки на PC, работающих под управлением DOS. Даже на этом
        "калеке" удавалось создавать неплохие сценарии, хотя
        это и требовало значительных усилий. Иногда еще возникает
        потребность в переносе пекетных файлов DOS на платформу UNIX, в
        виде сценариев командной оболочки. Обычно это не сложно,
        поскольку набор операторов, доступных в DOS, представляет из
        себя ограниченное подмножество эквивалентных команд, доступных
        в командной оболочке.</p>

        <div class="TABLE">
          <a name="AEN15143"></a>

          <p><strong>Таблица H-1. Ключевые слова/переменные/операторы
          пакетных файлов DOS и их аналоги командной
          оболочки</strong></p>

          <table border="1" class="CALSTABLE">
            <thead>
              <tr>
                <th align="left" valign="top">Операторы пакетных файлов</th>

                <th align="left" valign="top">Эквивалентные команды в UNIX</th>

                <th align="left" valign="top">Описание</th>
              </tr>
            </thead>

            <tbody>
              <tr>
                <td align="left" valign="top"><code class="OPTION">%</code></td>

                <td align="left" valign="top">$</td>

                <td align="left" valign="top">префикс аргументов командной строки</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">/</code></td>

                <td align="left" valign="top">-</td>

                <td align="left" valign="top">признак ключа (опции)</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">\</code></td>

                <td align="left" valign="top">/</td>

                <td align="left" valign="top">разделитель имен каталогов в пути</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">==</code></td>

                <td align="left" valign="top">=</td>

                <td align="left" valign="top">(равно) сравнение строк</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">!==!</code></td>

                <td align="left" valign="top">!=</td>

                <td align="left" valign="top">(не равно) сравнение строк</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">|</code></td>

                <td align="left" valign="top">|</td>

                <td align="left" valign="top">конвейер (канал)</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">@</code></td>

                <td align="left" valign="top">set <code class="OPTION">+v</code></td>

                <td align="left" valign="top">не выводить текущую команду</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">*</code></td>

                <td align="left" valign="top">*</td>

                <td align="left" valign="top"><span class="QUOTE">"шаблонный символ"</span> в
                имени файла</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">&gt;</code></td>

                <td align="left" valign="top">&gt;</td>

                <td align="left" valign="top">перенаправление (с удалением
                существующего файла)</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">&gt;&gt;</code></td>

                <td align="left" valign="top">&gt;&gt;</td>

                <td align="left" valign="top">перенаправление (с добавлением в конец
                существующего файла)</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">&lt;</code></td>

                <td align="left" valign="top">&lt;</td>

                <td align="left" valign="top">перенаправление ввода <code class="FILENAME">stdin</code></td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">%VAR%</code></td>

                <td align="left" valign="top">$VAR</td>

                <td align="left" valign="top">переменная окружения</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">REM</code></td>

                <td align="left" valign="top">#</td>

                <td align="left" valign="top">комментарий</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">NOT</code></td>

                <td align="left" valign="top">!</td>

                <td align="left" valign="top">отрицание последующего условия</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">NUL</code></td>

                <td align="left" valign="top"><code class="FILENAME">/dev/null</code></td>

                <td align="left" valign="top"><span class="QUOTE">"черная дыра"</span> для того,
                чтобы "спрятать" вывод команды</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">ECHO</code></td>

                <td align="left" valign="top">echo</td>

                <td align="left" valign="top">вывод (в Bash имеет большое число
                опций)</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">ECHO.</code></td>

                <td align="left" valign="top">echo</td>

                <td align="left" valign="top">вывод пустой строки</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">ECHO OFF</code></td>

                <td align="left" valign="top">set <code class="OPTION">+v</code></td>

                <td align="left" valign="top">не выводить последующие команды</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">FOR %%VAR IN (LIST) DO</code></td>

                <td align="left" valign="top">for var in [list]; do</td>

                <td align="left" valign="top">цикл <span class="QUOTE">"for"</span></td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">:LABEL</code></td>

                <td align="left" valign="top">эквивалент отсутствует (нет
                необходимости)</td>

                <td align="left" valign="top">метка</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">GOTO</code></td>

                <td align="left" valign="top">эквивалент отсутствует (используйте
                функции)</td>

                <td align="left" valign="top">переход по заданной метке</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">PAUSE</code></td>

                <td align="left" valign="top">sleep</td>

                <td align="left" valign="top">пауза, или ожидание, в течение заданного
                времени</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">CHOICE</code></td>

                <td align="left" valign="top">case или select</td>

                <td align="left" valign="top">выбор из меню</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">IF</code></td>

                <td align="left" valign="top">if</td>

                <td align="left" valign="top">условный оператор if</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">IF EXIST <code class="REPLACEABLE"><em>FILENAME</em></code></code></td>

                <td align="left" valign="top">if [ -e filename ]</td>

                <td align="left" valign="top">проверка существования файла</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">IF !%N==!</code></td>

                <td align="left" valign="top">if [ -z "$N" ]</td>

                <td align="left" valign="top">Проверка: параметр <span class="QUOTE">"N"</span> отсутствует</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">CALL</code></td>

                <td align="left" valign="top">source или . (оператор
                "точка")</td>

                <td align="left" valign="top"><span class="QUOTE">"подключение"</span> другого
                сценария</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">COMMAND /C</code></td>

                <td align="left" valign="top">source или . (оператор
                "точка")</td>

                <td align="left" valign="top"><span class="QUOTE">"подключение"</span> другого
                сценария (то же, что и CALL)</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">SET</code></td>

                <td align="left" valign="top">export</td>

                <td align="left" valign="top">установить переменную окружения</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">SHIFT</code></td>

                <td align="left" valign="top">shift</td>

                <td align="left" valign="top">сдвиг списка аргументов уомандной строки
                влево</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">SGN</code></td>

                <td align="left" valign="top">-lt или -gt</td>

                <td align="left" valign="top">знак (целого числа)</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">ERRORLEVEL</code></td>

                <td align="left" valign="top">$?</td>

                <td align="left" valign="top">код завершения</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">CON</code></td>

                <td align="left" valign="top"><code class="FILENAME">stdin</code></td>

                <td align="left" valign="top"><span class="QUOTE">"консоль"</span> (<code class="FILENAME">stdin</code>)</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">PRN</code></td>

                <td align="left" valign="top"><code class="FILENAME">/dev/lp0</code></td>

                <td align="left" valign="top">устройство принтера</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">LPT1</code></td>

                <td align="left" valign="top"><code class="FILENAME">/dev/lp0</code></td>

                <td align="left" valign="top">устройство принтера</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">COM1</code></td>

                <td align="left" valign="top"><code class="FILENAME">/dev/ttyS0</code></td>

                <td align="left" valign="top">первый последовательный порт</td>
              </tr>
            </tbody>
          </table>
        </div>

        <p>Пакетные файлы обычно содержат вызовы команд DOS. Они должны
        быть заменены эквивалентными командами UNIX.</p>

        <div class="TABLE">
          <a name="AEN15350"></a>

          <p><strong>Таблица H-2. Команды DOS и их эквиваленты в
          UNIX</strong></p>

          <table border="1" class="CALSTABLE">
            <thead>
              <tr>
                <th align="left" valign="top">Команды DOS</th>

                <th align="left" valign="top">Эувивалент в UNIX</th>

                <th align="left" valign="top">Описание</th>
              </tr>
            </thead>

            <tbody>
              <tr>
                <td align="left" valign="top"><code class="OPTION">ASSIGN</code></td>

                <td align="left" valign="top">ln</td>

                <td align="left" valign="top">ссылка на файл или каталог</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">ATTRIB</code></td>

                <td align="left" valign="top">chmod</td>

                <td align="left" valign="top">изменить атрибуты файла (права
                доступа)</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">CD</code></td>

                <td align="left" valign="top">cd</td>

                <td align="left" valign="top">сменить каталог</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">CHDIR</code></td>

                <td align="left" valign="top">cd</td>

                <td align="left" valign="top">сменить каталог</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">CLS</code></td>

                <td align="left" valign="top">clear</td>

                <td align="left" valign="top">очистить экран</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">COMP</code></td>

                <td align="left" valign="top">diff, comm, cmp</td>

                <td align="left" valign="top">сравнить файлы</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">COPY</code></td>

                <td align="left" valign="top">cp</td>

                <td align="left" valign="top">скопировать файл</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">Ctl-C</code></td>

                <td align="left" valign="top">Ctl-C</td>

                <td align="left" valign="top">прервать исполнение сценария</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">Ctl-Z</code></td>

                <td align="left" valign="top">Ctl-D</td>

                <td align="left" valign="top">EOF (конец-файла)</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">DEL</code></td>

                <td align="left" valign="top">rm</td>

                <td align="left" valign="top">удалить файл(ы)</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">DELTREE</code></td>

                <td align="left" valign="top">rm -rf</td>

                <td align="left" valign="top">удалить каталог с подкаталогами</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">DIR</code></td>

                <td align="left" valign="top">ls -l</td>

                <td align="left" valign="top">вывести содержимое каталога</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">ERASE</code></td>

                <td align="left" valign="top">rm</td>

                <td align="left" valign="top">удалить файл(ы)</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">EXIT</code></td>

                <td align="left" valign="top">exit</td>

                <td align="left" valign="top">завершить текущий процесс</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">FC</code></td>

                <td align="left" valign="top">comm, cmp</td>

                <td align="left" valign="top">сравнить файлы</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">FIND</code></td>

                <td align="left" valign="top">grep</td>

                <td align="left" valign="top">найти строку в файлах</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">MD</code></td>

                <td align="left" valign="top">mkdir</td>

                <td align="left" valign="top">создать каталог</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">MKDIR</code></td>

                <td align="left" valign="top">mkdir</td>

                <td align="left" valign="top">создать каталог</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">MORE</code></td>

                <td align="left" valign="top">more</td>

                <td align="left" valign="top">постраничный вывод</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">MOVE</code></td>

                <td align="left" valign="top">mv</td>

                <td align="left" valign="top">переместить</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">PATH</code></td>

                <td align="left" valign="top">$PATH</td>

                <td align="left" valign="top">путь поиска исполняемых файлов</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">REN</code></td>

                <td align="left" valign="top">mv</td>

                <td align="left" valign="top">переименовать (переместить)</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">RENAME</code></td>

                <td align="left" valign="top">mv</td>

                <td align="left" valign="top">переименовать (переместить)</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">RD</code></td>

                <td align="left" valign="top">rmdir</td>

                <td align="left" valign="top">удалить каталог</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">RMDIR</code></td>

                <td align="left" valign="top">rmdir</td>

                <td align="left" valign="top">удалить каталог</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">SORT</code></td>

                <td align="left" valign="top">sort</td>

                <td align="left" valign="top">отсортировать файл</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">TIME</code></td>

                <td align="left" valign="top">date</td>

                <td align="left" valign="top">вывести системное время</td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">TYPE</code></td>

                <td align="left" valign="top">cat</td>

                <td align="left" valign="top">вывести содержимое файла на <code class="FILENAME">stdout</code></td>
              </tr>

              <tr>
                <td align="left" valign="top"><code class="OPTION">XCOPY</code></td>

                <td align="left" valign="top">cp</td>

                <td align="left" valign="top">(расширенная команда) скопировать
                файл</td>
              </tr>
            </tbody>
          </table>
        </div>

        <div class="NOTE">
          <table class="NOTE" width="100%" border="0">
            <tbody><tr>
              <td width="25" align="center" valign="top"><img src="./Advanced Bash-Scripting Guide_files/note.gif" hspace="5" alt="Note"></td>

              <td align="left" valign="top">
                <p>Фактически, команды и операторы командной оболочки
                UNIX имеют огромное количество дополнительных опций,
                расширяющих их функциональность, по сравнению с их
                эквивалентами в DOS. В большинстве своем, пакетные
                файлы DOS предполагают наличие вспомогательных утилит,
                таких как <strong class="COMMAND">ask.com</strong> ("увечный"
                аналог UNIX-вого <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#READREF">read</a>).</p>

                <p>DOS поддерживает крайне ограниченный набор шаблонных
                символов, учавствующих в операциях <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GLOBBINGREF">подстановки имен файлов</a>,
                распознавая только два символа -- <span class="TOKEN">*</span> и <span class="TOKEN">?</span>.</p>
              </td>
            </tr>
          </tbody></table>
        </div>

        <p>Преобразование пакетных файлов DOS в сценарии командной
        оболочки, обычно не вызывает затруднений, а результат такого
        преобразования читается гораздо лучше, чем оригинал.</p>

        <div class="EXAMPLE">
          <a name="VIEWDAT"></a>

          <p><strong>Пример H-1. VIEWDATA.BAT: пакетный файл
          DOS</strong></p>
<pre class="PROGRAMLISTING">REM VIEWDATA

REM INSPIRED BY AN EXAMPLE IN "DOS POWERTOOLS"
REM                           BY PAUL SOMERSON


@ECHO OFF

IF !%1==! GOTO VIEWDATA
REM  IF NO COMMAND-LINE ARG...
FIND "%1" C:\BOZO\BOOKLIST.TXT
GOTO EXIT0
REM  PRINT LINE WITH STRING MATCH, THEN EXIT.

:VIEWDATA
TYPE C:\BOZO\BOOKLIST.TXT | MORE
REM  SHOW ENTIRE FILE, 1 PAGE AT A TIME.

:EXIT0
</pre>
        </div>

        <p>Результат преобразования в сценарий командной оболочки,
        немного улучшенный.</p>

        <div class="EXAMPLE">
          <a name="VIEWDATA"></a>

          <p><strong>Пример H-2. viewdata.sh: Результат преобразования
          VIEWDATA.BAT в сценарий командной оболочки</strong></p>
<pre class="PROGRAMLISTING">#!/bin/bash
# Результат преобразования пакетного файла VIEWDATA.BAT в сценарий командной оболочки.

DATAFILE=/home/bozo/datafiles/book-collection.data
ARGNO=1

# @ECHO OFF       Эта команда здесь не нужна.

if [ $# -lt "$ARGNO" ]    # IF !%1==! GOTO VIEWDATA
then
  less $DATAFILE          # TYPE C:\MYDIR\BOOKLIST.TXT | MORE
else
  grep "$1" $DATAFILE     # FIND "%1" C:\MYDIR\BOOKLIST.TXT
fi

exit 0                    # :EXIT0

# операторы перехода GOTO, метки и прочий "мусор" больше не нужны.
# Результат преобразования стал короче, чище и понятнее,
</pre>
        </div>

        <p>На сайте Тэда Дэвиса (Ted Davis) <!--noindex--><a href="http://www.maem.umr.edu/~batch/" target="_top">Shell Scripts on the PC</a><!--/noindex-->, вы найдете большое
        число руководств по созданию пакетных файлов в DOS.
        Определенно, его изобретательность будет вам полезна, при
        создании ваших сценариев.</p>
      </div>

      <div class="APPENDIX">
        <hr>

        <h1><a name="EXERCISES"></a>Приложение I. Упражнения</h1>

        <div class="SECT1">
          <h2 class="SECT1"><a name="SCRIPTANALYSIS"></a>I.1. Анализ сценариев</h2>

          <p>Просмотрите следующие сценарии. Попробуйте запустить их,
          затем объясните -- что они делают. Расставьте комментарии,
          затем попробуйте записать их в более компактном виде.</p>
<pre class="PROGRAMLISTING">#!/bin/bash

MAX=10000


  for((nr=1; nr&lt;$MAX; nr++))
  do

    let "t1 = nr % 5"
    if [ "$t1" -ne 3 ]
    then
      continue
    fi

    let "t2 = nr % 7"
    if [ "$t2" -ne 4 ]
    then
      continue
    fi

    let "t3 = nr % 9"
    if [ "$t3" -ne 5 ]
    then
      continue
    fi

  break   # Что произойдет, если закомментировать эту строку? Почему?

  done

  echo "Число = $nr"


exit 0
</pre>
          <br>
          <br>

          <p>---</p>

          <p>Читатель прислал следующий кусок кода.</p>
<pre class="PROGRAMLISTING">while read LINE
do
  echo $LINE
done &lt; `tail -f /var/log/messages`
</pre>
          Он предполагал написать сценарий, который отслеживал бы
          изменения в системном журнале <code class="FILENAME">/var/log/messages</code>. К сожалению, этот
          код "зависает" и не делает ничего полезного.
          Почему? Найдите ошибку и исправьте ее (подсказка: вместо
          операции <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#REDIRREF">перенаправления <code class="FILENAME">stdin</code> в цикл</a>, попробуйте
          использовать <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PIPEREF">конвейерную обработку</a>).<br>
          <br>

          <p>---</p>

          <p>Просмотрите сценарий <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LIFESLOW">Пример A-11</a>, попробуйте изменить его
          таким образом, чтобы он выглядел проще и логичнее. Удалите
          все "лишние" переменные и попытайтесь
          оптимизировать сценарий по скорости исполнения.</p>

          <p>Измените сценарий таким образом, чтобы он мог принимать
          начальную установку "поколения 0" из любого
          текстового файла. Сценарий должен считать первые <code class="VARNAME">$ROW*$COL</code> символов, и на место гласных
          вставлять "живые особи". Подсказка: не забудьте
          преобразовать пробелы в символы подчеркивания.</p>
        </div>

        <div class="SECT1">
          <hr>

          <h2 class="SECT1"><a name="WRITINGSCRIPTS"></a>I.2. Создание сценариев</h2>

          <p><a name="WRITINGSCRIPTS1"></a></p>

          <p>Напишите сценарии для выполнения повседневных задач.</p>

          <div class="VARIABLELIST">
            <p><strong><a name="EXEASY1"></a>Простые задания</strong></p>

            <dl>
              <dt><strong class="COMMAND">Содержимое домашнего
              каталога</strong></dt>

              <dd>
                <p>Выполните рекурсивный обход домашнего каталога и
                сохраните информацию в файл. Сожмите файл. Попросите
                пользователя вставить дискету и нажать клавишу <strong class="KEYCAP">ENTER</strong>. Запишите сжатый файл на
                дискету.</p>
              </dd>

              <dt><strong class="COMMAND">Замена цикла <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FORLOOPREF1">for</a> циклами <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WHILELOOPREF">while</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#UNTILLOOPREF">until</a></strong></dt>

              <dd>
                <p>Замените <span class="emphasis"><em class="EMPHASIS">циклы for</em></span> в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX22">Пример 10-1</a> на <span class="emphasis"><em class="EMPHASIS">while</em></span>. Подсказка:
                запишите данные в <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ARRAYREF">массив</a> и пройдите в цикле по
                элементам массива.</p>

                <p>Выполнив эту <span class="QUOTE">"тяжелую работу"</span>,
                замените циклы, в этом примере, на циклы <span class="emphasis"><em class="EMPHASIS">until</em></span> .</p>
              </dd>

              <dt><strong class="COMMAND">Изменение межстрочного интервала в
              текстовом файле</strong></dt>

              <dd>
                <p>Напишите сценарий, который будет читать текст из
                заданного файла, и выводить, построчно, на <code class="FILENAME">stdout</code>, добавляя при этом
                дополнительные пустые строки так, чтобы в результате
                получился вывод с <span class="emphasis"><em class="EMPHASIS">двойным межстрочным
                интервалом</em></span>.</p>

                <p>Добавьте код, который будет выполнять проверку
                наличия файла, передаваемого как аргумент.</p>

                <p>Когда сценарий будет отлажен, измените его так,
                чтобы он выводил текстовый файл с <span class="emphasis"><em class="EMPHASIS">тройным межстрочным
                интервалом</em></span>.</p>

                <p>И наконец, напишите сценарий, который будет удалять
                пустые строки из заданного файла.</p>
              </dd>

              <dt><strong class="COMMAND">Вывод
              "задом-на-перед"</strong></dt>

              <dd>
                <p>Напишите сценарий, который будет выводить себя на
                <code class="FILENAME">stdout</code>, но <span class="emphasis"><em class="EMPHASIS">в обратном порядке</em></span>.</p>
              </dd>

              <dt><strong class="COMMAND">Автоматическое
              разархивирование</strong></dt>

              <dd>
                <p>Для каждого файла, из заданного списка, сценарий
                должен определить тип архиватора, которым был создан
                тот или иной файл (с помощью утилиты <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FILEREF">file</a>). Затем сценарий должен
                выполнить соответствующую команду разархивации (<strong class="COMMAND">gunzip</strong>, <strong class="COMMAND">bunzip2</strong>, <strong class="COMMAND">unzip</strong>, <strong class="COMMAND">uncompress</strong> или что-то иное).
                Если файл не является архивом, то сценарий должен
                оповестить пользователя об этом и ничего не делать с
                этим файлом.</p>
              </dd>

              <dt><strong class="COMMAND">Уникальный идентификатор
              системы</strong></dt>

              <dd>
                <p>Сценарий должен сгенерировать <span class="QUOTE">"уникальный"</span> 6-ти
                разрядный шестнадцатиричный идентификатор системы.
                <span class="emphasis"><em class="EMPHASIS">Не</em></span> пользуйтесь дефектной
                утилитой <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#HOSTIDREF">hostid</a>. Подсказка: <strong class="COMMAND"><a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MD5SUMREF">md5sum</a> <code class="FILENAME">/etc/passwd</code></strong>, затем
                отберите первые 6 цифр.</p>
              </dd>

              <dt><strong class="COMMAND">Резервное копирование</strong></dt>

              <dd>
                <p>Сценарий должен создать архив (<code class="FILENAME">*.tar.gz</code>) всех файлов в домашнем
                каталоге пользователя (<code class="FILENAME">/home/user-name</code>), которые
                изменялись в течение последних 24 часов. Подсказка:
                воспользуйтесь утилитой <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FINDREF">find</a>.</p>
              </dd>

              <dt><strong class="COMMAND">Простые числа</strong></dt>

              <dd>
                <p>Сценарий должен вывести (на stdout) все простые
                числа, в диапазоне от 60000 до 63000. Вывод должен быть
                отформатирован по столбцам (подсказка: воспользуйтесь
                командой <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PRINTFREF">printf</a>).</p>
              </dd>

              <dt><strong class="COMMAND">Лототрон</strong></dt>

              <dd>
                <p>Сценарий должен имитировать работу лототрона --
                извлекать 5 случайных неповторяющихся чисел в диапазоне
                1 - 50. Сценарий должен предусматривать как вывод на
                <code class="FILENAME">stdout</code>, так и запись чисел в
                файл, кроме того, вместе с числами должны выводиться
                дата и время генерации данного набора.</p>
              </dd>
            </dl>
          </div>

          <div class="VARIABLELIST">
            <p><strong><a name="EXMEDIUM1"></a>Задания повышенной
            сложности</strong></p>

            <dl>
              <dt><strong class="COMMAND">Управление дисковым
              пространством</strong></dt>

              <dd>
                <p>Сценарий должен отыскать в домашнем каталоге
                пользователя <code class="FILENAME">/home/username</code> файлы, имеющие
                размер больше 100K. Каждый раз предоставляя
                пользователю возможность удалить или сжать этот файл,
                затем переходить к поиску следующего файла.</p>
              </dd>

              <dt><strong class="COMMAND">Безопасное удаление</strong></dt>

              <dd>
                <p>Напишите сценарий <span class="QUOTE">"безопасного"</span> удаления
                файлов -- <code class="FILENAME">srm.sh</code>. Файлы, с именами,
                передаваемыми этому сценарию, не должны удаляться,
                вместо этого, файлы следует сжать утилитой <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GZIPREF">gzip</a>, если они еще не сжаты (не
                забывайте про утилиту <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FILEREF">file</a>), и переместить в каталог <code class="FILENAME">/home/username/trash</code>. При
                старте, сценарий должен удалять из каталога <span class="QUOTE">"trash"</span> файлы, которые
                были созданы более 48 часов тому назад.</p>
              </dd>

              <dt><strong class="COMMAND">Размен монет</strong></dt>

              <dd>
                <p>Как более рационально собрать сумму в $1.68,
                используя только монеты, с номиналом не выше 25c? Это
                будет шесть 25-ти центовых монет, одна десятицентовая,
                одна пятицентовая и три монеты достоинством в 1
                цент.</p>

                <p>Учитывая возможность произвольного ввода суммы в
                долларах и центах ($*.??), найдите такую комбинацию,
                которая требовала бы наименьшее число монет. Если вы
                проживаете не в США, то можете использовать свою
                денежную единицу и номиналы монет. Подсказка: взгляните
                на <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX61">Пример 22-4</a>.</p>
              </dd>

              <dt><strong class="COMMAND">Корни квадратного
              уравнения</strong></dt>

              <dd>
                <p>Напишите сценарий, который находил бы корни <span class="QUOTE">"квадратного "</span>
                уравнения, вида: <span class="emphasis"><em class="EMPHASIS">Ax^2 + Bx + C = 0</em></span>.
                Сценарий должен получать коэффициенты уравнения <code class="USERINPUT"><strong>A</strong></code>, <code class="USERINPUT"><strong>B</strong></code> и <code class="USERINPUT"><strong>C</strong></code>, как
                аргументы командной строки, и находить корни, с
                точностью до четвертого знака после запятой.</p>

                <p>Подсказка: воспользуйтесь <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BCREF">bc</a>, для нахождения решения по хорошо
                известной формуле: <span class="emphasis"><em class="EMPHASIS">x = ( -B +/- sqrt( B^2 - 4AC ) ) /
                2A</em></span>.</p>
              </dd>

              <dt><strong class="COMMAND">Сумма чисел</strong></dt>

              <dd>
                <p>Найдите сумму всех пятизначных чисел (в диапазоне
                10000 - 99999), которые содержат <span class="emphasis"><em class="EMPHASIS">точно две</em></span> цифры из
                следующего набора: { 4, 5, 6 }.</p>

                <p>Примеры чисел, удовлетворяющих данному условию:
                42057, 74638 и 89515.</p>
              </dd>

              <dt><strong class="COMMAND">Счастливый билет</strong></dt>

              <dd>
                <p>"Счастливым" считается такой билет, в
                котором последовательное сложение цифр номера дает
                число 7. Например, 62431 -- номер
                "счастливого" билета (6 + 2 + 4 + 3 + 1 = 16,
                1 + 6 = 7). Найдите все "счастливые" номера,
                располагающиеся в диапазоне 1000 - 10000.</p>
              </dd>

              <dt><strong class="COMMAND">Синтаксический анализ</strong></dt>

              <dd>
                <p>Проанализируйте файл <code class="FILENAME">/etc/passwd</code> и выведите его
                содержимое в табличном виде.</p>
              </dd>

              <dt><strong class="COMMAND">Просмотр файла с данными</strong></dt>

              <dd>
                <p>Некоторые базы данных и электронные таблицы
                используют формат CSV (<span class="emphasis"><em class="EMPHASIS">comma-separated values</em></span>),
                для хранения данных в файлах. Зачастую, эти файлы
                должны анализироваться другими приложениями.</p>

                <p>Пусть файл содержит следующие данные:</p>
<pre class="PROGRAMLISTING">Jones,Bill,235 S. Williams St.,Denver,CO,80221,(303) 244-7989
Smith,Tom,404 Polk Ave.,Los Angeles,CA,90003,(213) 879-5612
...
</pre>
                Прочитайте данные и выведите их на <code class="FILENAME">stdout</code> в виде колонок с
                заголовками.<br>
                <br>
              </dd>

              <dt><strong class="COMMAND">Выравнивание</strong></dt>

              <dd>
                <p>Текст вводится с устройства <code class="FILENAME">stdin</code> или из файла. Его
                необходимо вывести на <code class="FILENAME">stdout</code>, с выравниванием по
                ширине, используя задаваемую пользователем ширину
                строк.</p>
              </dd>

              <dt><strong class="COMMAND">Список рассылки</strong></dt>

              <dd>
                <p>Напишите сценарий, который использовал бы команду <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COMMMAIL1">mail</a>, для управления простым
                списком рассылки. Сценарий должен брать текст
                ежемесячного информационного бюллетеня из заданного
                файла, список адресатов из другого файла и выполнять
                рассылку новостей по электронной почте.</p>
              </dd>

              <dt><strong class="COMMAND">Пароли</strong></dt>

              <dd>
                <p>Сгенерируйте псевдослучайные 8-ми символьные пароли,
                используя символы из диапазона [0-9], [A-Z], [a-z].
                Каждый пароль должен содержать не менее 2-х цифр.</p>
              </dd>
            </dl>
          </div>

          <div class="VARIABLELIST">
            <p><strong><a name="EXDIFFICULT1"></a>Сложные задания</strong></p>

            <dl>
              <dt><strong class="COMMAND">Регистрация обращений к
              файлам</strong></dt>

              <dd>
                <p>Попробуйте отследить все попытки обращения к файлам
                в каталоге <code class="FILENAME">/etc</code>, в течение дня. Сведения,
                которые включают в себя время обращения, имя файла, имя
                пользователя (если имели место какие либо изменения в
                файлах, то они тоже должны быть отмечены), запишите в
                виде аккуратно отформатированных записей в логфайл.</p>
              </dd>

              <dt><strong class="COMMAND">Удаление комментариев</strong></dt>

              <dd>
                <p>Удалите все комментарии из сценария, имя которого
                задается с командной строки. При этом, строка <span class="QUOTE">"#! /bin/bash"</span> не
                должна удаляться.</p>
              </dd>

              <dt><strong class="COMMAND">Преобразование в HTML</strong></dt>

              <dd>
                <p>Преобразуйте заданный текстовый файл в HTML формат.
                Этот сценарий должен автоматически вставлять
                необходимые теги HTML в тело файла.</p>
              </dd>

              <dt><strong class="COMMAND">Удаление тегов HTML</strong></dt>

              <dd>
                <p>Удалите все теги HTML из заданного HTML файла, затем
                переформатируйте его так, чтобы строки не были короче
                60 и длиннее 75 символов. Предусмотрите оформление
                параграфов. Преобразуйте таблицы HTML в их
                приблизительный текстовый эквивалент.</p>
              </dd>

              <dt><strong class="COMMAND">Преобразование XML файлов</strong></dt>

              <dd>
                <p>Преобразуйте файл из формата XML в формат HTML и в
                простой текстовый файл.</p>
              </dd>

              <dt><a name="CSPAMMERS"></a><strong class="COMMAND">Борьба со спамом</strong></dt>

              <dd>
                <p>Напишите сценарий, который анализировал бы входящие
                почтовые сообщения на принадлежность к спаму и
                отыскивал бы в DNS имена узлов сети, по IP адресам из
                заголовка письма. Сценарий должен отправлять найденые
                спамерские сообщения ответственным за спам провайдерам
                (ISP). Естественно, вы должны отфильтровать <span class="emphasis"><em class="EMPHASIS">свой собственный IP
                адрес</em></span>, чтобы не случилось так, что вы
                жалуетесь на самого себя.</p>

                <p>По мере необходимости, используйте соответствующие
                <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#COMMUNINFO1">команды для работы с
                сетью</a>.</p>
              </dd>

              <dt><strong class="COMMAND">Азбука Морзе</strong></dt>

              <dd>
                <p>Преобразуйте текстовый файл в код Морзе. Символы из
                файла должны быть представлены в виде, соответствующих
                им, кодов Морзе, состоящих из точек и тире, и
                разделенных пробелами. Например, <span class="QUOTE">"script"</span> ===&gt; <span class="QUOTE">"... _._. ._. .. .__.
                _"</span>.</p>
              </dd>

              <dt><strong class="COMMAND">Шестнадцатиричный дамп</strong></dt>

              <dd>
                <p>Выведите, в виде шестнадцатиричного дампа,
                содержимое бинарного файла, передаваемого в сценарий,
                как аргумент командной строки. Вывод должен
                производиться в четкой табличной форме, первое поле
                таблицы -- адрес, далее должны следовать 8 полей,
                содержащие 4-х байтовые шестнадцатиричные числа, а
                завершать строку должно поле, содержащее эквивалентное
                отображение 8-ми предшествующих полей, в виде
                ASCII-символов.</p>
              </dd>

              <dt><strong class="COMMAND">Эмуляция сдвигового
              регистра</strong></dt>

              <dd>
                <p>Используя <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#STACKEX">Пример 25-9</a>, как образец, напишите
                сценарий, который эмулировал бы 64-х битный сдвиговый
                регистр в виде <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ARRAYREF">массива</a>. Реализуйте функции <span class="emphasis"><em class="EMPHASIS">загрузки</em></span> значения в
                регистр, <span class="emphasis"><em class="EMPHASIS">сдвиг влево</em></span> и <span class="emphasis"><em class="EMPHASIS">сдвиг вправо</em></span>. В
                заключение, напишите функцию, которая интерпретировала
                бы содержимое "регистра" как восемь 8-ми
                битных символов ASCII.</p>
              </dd>

              <dt><strong class="COMMAND">Детерминант (определитель)</strong></dt>

              <dd>
                <p>Найдите детерминант (определитель) матрицы 4 x
                4.</p>
              </dd>

              <dt><strong class="COMMAND">Анаграммы</strong></dt>

              <dd>
                <p>Сценарий должен запросить у пользователя 4-х
                символьное слово, и найти анаграммы для этого слова.
                Например, анаграммы к слову <span class="emphasis"><em class="EMPHASIS">word</em></span>: <span class="emphasis"><em class="EMPHASIS">do or rod row word</em></span>. Для
                поиска анаграмм можете использовать файл <code class="FILENAME">/usr/share/dict/linux.words</code>.</p>
              </dd>

              <dt><strong class="COMMAND">Индекс сложности текста</strong></dt>

              <dd>
                <p><span class="QUOTE">"Индекс сложности
                текста"</span> оценивает трудность понимания
                текста, как некое число, которое грубо соответствует
                количеству лет обучения в общеобразовательной школе.
                Например, индекс равный 8-ми говорит о том, что текст
                доступен для понимания человеку, окончившему 8-й класс
                общеобразовательной школы.</p>

                <p>Вычисление индекса ведется по следующему
                алгоритму.</p>

                <ol type="1">
                  <li>
                    <p>Выберите кусок текста, длиной не менее 100
                    слов.</p>
                  </li>

                  <li>
                    <p>Сосчитайте количество предложений.</p>
                  </li>

                  <li>
                    <p>Найдите среднее число слов в предложении.</p>

                    <p>СРЕДНЕЕ_ЧИСЛО_СЛОВ = ОБЩЕЕ_ЧИСЛО_СЛОВ /
                    ЧИСЛО_ПРЕДЛОЖЕНИЙ</p>
                  </li>

                  <li>
                    <p>Сосчитайте количество <span class="QUOTE">"трудных"</span> слов --
                    которые содержат не менее 3-х слогов. Разделите это
                    число на общее количество слов, в результате вы
                    получите пропорцию сложных слов.</p>

                    <p>ПРОПОРЦИЯ_СЛОЖНЫХ_СЛОВ = ЧИСЛО_ДЛИННЫХ_СЛОВ /
                    ОБЩЕЕ_ЧИСЛО_СЛОВ</p>
                  </li>

                  <li>
                    <p>Индекс сложности текста рассчитывается как сумма
                    двух этих чисел, умноженная на 0.4 и округленная до
                    ближайшего целого.</p>

                    <p>ИНДЕКС_СЛОЖНОСТИ = int ( 0.4 * (
                    СРЕДНЕЕ_ЧИСЛО_СЛОВ + ПРОПОРЦИЯ_СЛОЖНЫХ_СЛОВ ) )</p>
                  </li>
                </ol>

                <p>4-й пункт -- самый сложный. Существуют различные
                алгоритмы подсчета слогов в словах. В данном же случае,
                вы можете ограничиться подсчетом сочетаний
                "гласный-согласный".</p>

                <p>Строго говоря, при расчете индекса сложности не
                следует считать составные слова и имена собственные как
                <span class="QUOTE">"сложные"</span> слова, но это
                слишком усложнит сценарий.</p>
              </dd>

              <dt><strong class="COMMAND">Вычисление числа пи по алгоритму
              "Игла Баффона"</strong></dt>

              <dd>
                <p>В 18 веке, французский математик де Баффон (de
                Buffon) проделывал эксперимент, который заключался в
                бросании иглы, длиной <span class="QUOTE">"n"</span>, на деревянный пол,
                собраный из длинных и узких досок. Ширина всех досок
                пола одинакова и равна <span class="QUOTE">"d"</span>. Оказалось, что
                отношение общего числа бросков, к числу бросков, когда
                игла ложилась на щель, кратно числу пи.</p>

                <p>Пользуясь <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CANNON">Пример 12-35</a>, напишите сценарий,
                который использовал бы метод Монте Карло для эмуляции
                "Иглы Баффона". Для простоты примите длину
                иглы раной ширине досок, <span class="emphasis"><em class="EMPHASIS">n = d</em></span>.</p>

                <p>Подсказка: особое значение здесь имеют переменные,
                которые будут вычисляться как расстояние от центра иглы
                до ближайшей щели и величина угла между иглой и щелью.
                Для выполнения расчетов можно воспользоваться утилитой
                <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BCREF">bc</a>.</p>
              </dd>

              <dt><strong class="COMMAND">Шифрование по алгоритму
              Playfair</strong></dt>

              <dd>
                <p>Напишите сценарий, реализующий алгоритм шифрования
                Playfair (Wheatstone).</p>

                <p>В соответствии с этим алгоритмом, текст шифруется
                путем замены каждой 2-х символьной последовательности
                -- <span class="QUOTE">"диграммы"</span>.
                Традиционно, в качестве ключа, используется матрица
                символов алфавита 5 x 5.</p>
<pre class="PROGRAMLISTING">   C O D E S
   A B F G H
   I K L M N
   P Q R T U
   V W X Y Z
            
</pre>
                Матрица содержит все символы алфавита, за исключением
                символа "J", который представляет символ
                "I". Первая строка матрицы -- произвольно
                выбранное слово, в данном случае -- "CODES",
                далее следуют символы алфавита, исключая те, которые
                входят в состав первой строки.<br>
                <br>

                <p>Шифрование производится по следующему алгоритму: для
                начала, текст сообщения разбивается на диграммы (группы
                по 2 символа). Если в диграмму попадают два одинаковых
                символа, то второй символ удаляется, и формируется
                новая диграмма. Если в последней группе остается один
                символ, то такая "неполная" диграмма
                дополняется "пустым" символом, обычно
                "X".</p>
<pre class="PROGRAMLISTING">THIS IS A TOP SECRET MESSAGE

TH IS IS AT OP SE CR ET ME SA GE
            
</pre>
                Каждая диграмма может подпадать под одно из следующих
                определений:.<br>
                <br>

                <p>1) Оба символа находятся в одной строке ключа.
                Тогда, каждый из них заменяется символом, стоящим
                справа в той же строке. Если это последний символ
                строки ключа, то он заменяется первым символом в той же
                строке ключа.</p>

                <p>2) Оба символа находятся в одном столбце ключа.
                Тогда каждый из них заменяется на символ, стоящий ниже,
                в этом же столбце. Если это последний символ в столбце
                ключа, то он заменяется первым символом в том же
                столбце ключа.</p>

                <p>3) Символы диграммы стоят в вершинах прямоугольника.
                Тогда каждый из них заменяется символом из соседнего,
                по горизонтали, угла.</p>

                <p>Диграмма "TH" соответствует 3-му
                определению.</p>
<pre class="PROGRAMLISTING">G H
M N
T U           (Прямоугольник с вершинами "T" и "H")

T --&gt; U
H --&gt; G

            
</pre>
                <br>
                <br>

                <p>Диграмма "SE" соответствует 1-му
                определению.</p>
<pre class="PROGRAMLISTING">C O D E S     (Строка содержит оба символа "S" и "E")

S --&gt; C  (замена на первый символ в строке ключа)
E --&gt; S
            
</pre>
                <br>
                <br>

                <p>
Дешифрация выполняется обратной процедурой, для
                случаев 1 и 2 -- замена символом стоящим левее/выше.
                Для случая 3 -- аналогично шифрации, т.е. заменяется
                символом из соседнего, по горизонтали, угла. Helen
                Fouche Gaines, в своей классической работе
                "Elementary Cryptoanalysis" (1939), приводит
                подробное описание алгоритма Playfair и методы его
                реализации.</p>

                <p>Этот сценарий должен иметь три основных раздела</p>

                <ol type="I">
                  <li>
                    <p>Генерация <span class="QUOTE">"ключевой матрицы"</span>,
                    основывающейся на слове, которое вводит
                    пользователь.</p>
                  </li>

                  <li>
                    <p>Шифрование <span class="QUOTE">"плоского"</span> текста
                    сообщения.</p>
                  </li>

                  <li>
                    <p>Дешифрование зашифрованного текста.</p>
                  </li>
                </ol>

                <p>Широкое применение, в этом сценарии, найдут <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#ARRAYREF">массивы</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FUNCTIONREF">функции</a>.</p>
              </dd>
            </dl>
          </div>

          <p>--</p>

          <p>Пожалуйста, не присылайте автору свои варианты решения
          упражнений. Если вы хотите впечатлить его своим умом и
          сообразительностью -- присылайте обнаруженные вами ошибки и
          предложения по улучшению этой книги.</p>
        </div>
      </div>

      <div class="APPENDIX">
        <hr>

        <h1><a name="COPYRIGHT"></a>Приложение J. Авторские права</h1>

        <p>Авторские права на книгу <span class="QUOTE">"Advanced Bash-Scripting
        Guide"</span>, принадлежат Менделю Куперу (Mendel Cooper).
        Этот документ может распространяться исключительно на условиях
        Open Publication License (версия 1.0 или выше), <!--noindex--><a href="http://www.opencontent.org/openpub/" target="_top">http://www.opencontent.org/openpub/</a><!--/noindex-->.
        Соблюдение следующих пунктов лицензии обязательно.</p>

        <ol type="1">
          <li>
            <p>Распространение существенно измененных версий этого
            документа, запрещено без явного разрешения держателя
            прав.</p>
          </li>

          <li>
            <p>Запрещено распространение твердых (бумажных) копий
            книги, или ее производных, без явного согласия держателя
            прав.</p>
          </li>
        </ol>

        <p><span class="emphasis"><em class="EMPHASIS">Пункт 1</em></span>, выше, явно запрещает
        вставлять в текст документа логотипы компаний или навигационные
        элементы, за исключением</p>

        <ol type="1">
          <li>
            <p>Некоммерческих организаций, таких как <!--noindex--><a href="http://www.tldp.org/" target="_top">Linux Documentation Project</a><!--/noindex--> и <!--noindex--><a href="http://ibiblio.org/" target="_top">Sunsite</a><!--/noindex-->.</p>
          </li>

          <li>
            <p>Не <span class="QUOTE">"запятнавших"</span> себя
            дистрибутивостроителей Linux, таких как Debian, Red Hat,
            Mandrake и других.</p>
          </li>
        </ol>

        <p>Практически, вы можете свободно распространять <span class="emphasis"><em class="EMPHASIS">неизмененную</em></span> электронную версию
        этой книги. Вы должны получить явное разрешение автора на
        распространение измененных версий книги или ее производных.
        Цель этого ограничения состоит в том, чтобы сохранить
        художественную целостность данного документа и предотвратить
        появление побочных <span class="QUOTE">"ветвей"</span>.</p>

        <p>Это очень либеральные условия и они не должны препятствовать
        законному распространению и использованию этой книги. Автор
        особенно поощряет использование этой книги в учебных целях.</p>

        <p>Права на коммерческое распространение книги могут быть
        получены у <a href="mailto:thegrendel@theriver.com" target="_top">автора</a>.</p>

        <p>Автор произвел этот документ в соответствии с буквой и духом
        <!--noindex--><a href="http://www.tldp.org/manifesto.html" target="_top">LDP Manifesto</a><!--/noindex-->.</p>

        <p>Hyun Jin Cha завершил <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html" "http:="" kldp.org="" howto="" html="" adv-bash-scr-howto="" index.html"="" target="_top">перевод на Корейский язык</a> версию 1.0.11 этой
        книги. Переводы на Испанский, Португальский, Французский,
        Немецкий, Итальянский и Китайский языки находятся на стадии
        реализации. Если вы изъявите желание перевести этот документ на
        другой язык, то можете свободно выполнить этот перевод,
        основываясь на условиях, заявленных выше. В этом случае, автор
        хотел бы, чтобы его поставили в известность.</p>

        <table class="SIDEBAR" border="1" cellpadding="5">
          <tbody><tr>
            <td>
              <div class="SIDEBAR">
                <a name="AEN15890"></a>

                <p>Linux -- это торговая марка, принадлежащая Линусу
                Торвальдсу (Linus Torvalds).</p>

                <p>Unix и UNIX -- это торговая марка, принадлежащая
                Open Group.</p>

                <p>MS Windows -- это торговая марка, принадлежащая
                Microsoft Corp.</p>

                <p>Все другие коммерческие торговые марки, упомянутые в
                данном документе, принадлежат их владельцам.</p>
              </div>
            </td>
          </tr>
        </tbody></table>
      </div>
    </div>

    <h3 class="FOOTNOTES">Примечания</h3>

    <table border="0" class="FOOTNOTES" width="100%">
      <tbody><tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN123" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN123"><span class="footnote">[1]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Их так же называют <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BUILTINREF">встроенными</a> конструкциями языка
          командной оболочки shell.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN165" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN165"><span class="footnote">[2]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Многие особенности <span class="emphasis"><em class="EMPHASIS">ksh88</em></span> и даже <span class="emphasis"><em class="EMPHASIS">ksh93</em></span> перекочевали в Bash.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN172" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN172"><span class="footnote">[3]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>В соответствии с соглашениями, имена файлов с
          shell-скриптами, такими как Bourne shell и совместимыми,
          имеют расширение <code class="FILENAME">.sh</code>. Все стартовые скрипты, которые вы
          найдете в <code class="FILENAME">/etc/rc.d</code>, следуют этому
          соглашению.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN199" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN199"><span class="footnote">[4]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Некоторые разновидности UNIX (основанные на 4.2BSD)
          требуют, чтобы эта последовательность состояла из 4-х байт,
          за счет добавления пробела после <span class="TOKEN">!</span>, <code class="USERINPUT"><strong>#! /bin/sh</strong></code>.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN207" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN207"><span class="footnote">[5]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>В shell-скриптах последовательность <span class="TOKEN">#!</span> должна стоять самой первой и задает
          интерпретатор (<strong class="COMMAND">sh</strong> или <strong class="COMMAND">bash</strong>). Интерпретатор, в свою
          очередь, воспринимает эту строку как комментарий, поскольку
          она начинается с символа <span class="TOKEN">#</span>.</p>

          <p>Если в сценарии имеются еще такие же строки, то они
          воспринимаются как обычный комментарий.</p>
<pre class="PROGRAMLISTING">#!/bin/bash

echo "Первая часть сценария."
a=1

#!/bin/bash
# Это *НЕ* означает запуск нового сценария.

echo "Вторая часть сценария."
echo $a  # Значение переменной $a осталось равно 1.
</pre>
          <br>
          <br>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN220" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN220"><span class="footnote">[6]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Эта особенность позволяет использовать различные
          хитрости.</p>
<pre class="PROGRAMLISTING">#!/bin/rm
# Самоуничтожающийся сценарий.

# Этот скрипт ничего не делает -- только уничтожает себя.

WHATEVER=65

echo "Эта строка никогда не будет напечатана."

exit $WHATEVER  # Не имеет смысла, поскольку работа сценария завершается не здесь.
</pre>
          <br>
          <br>

          <p>Попробуйте запустить файл <code class="FILENAME">README</code> с сигнатурой <code class="USERINPUT"><strong>#!/bin/more</strong></code>
          (предварительно не забудьте сделать его исполняемым).</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN230" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN230"><span class="footnote">[7]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p><span class="strong"><strong class="EMPHASIS">P</strong></span>ortable <span class="strong"><strong class="EMPHASIS">O</strong></span>perating <span class="strong"><strong class="EMPHASIS">S</strong></span>ystem <span class="bold"><strong class="EMPHASIS">I</strong></span>nterface, попытка
          стандартизации UNI<span class="strong"><strong class="EMPHASIS">X</strong></span>-подобных операционных
          систем.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN253" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN253"><span class="footnote">[8]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Внимание: вызов Bash-скрипта с помощью команды <code class="USERINPUT"><strong>sh scriptname</strong></code>
          отключает специфичные для Bash расширения, что может привести
          к появлению ошибки и аварийному завершению работы
          сценария.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN266" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN266"><span class="footnote">[9]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Сценарий должен иметь как право на исполнение, так и право
          на <span class="emphasis"><em class="EMPHASIS">чтение</em></span>, поскольку shell должен
          иметь возможность прочитать скрипт.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN278" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN278"><span class="footnote">[10]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Почему бы не запустить сценарий просто набрав название
          файла <code class="USERINPUT"><strong>scriptname</strong></code>, если
          сценарий находится в текущем каталоге? Дело в том, что из
          соображений безопасности, путь к текущему каталогу <span class="QUOTE">"."</span> не включен в переменную
          окружения <code>$PATH</code>. Поэтому необходимо явно указывать
          путь к текущему каталогу, в котором находится сценарий, т.е.
          <code class="USERINPUT"><strong>./scriptname</strong></code>.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN901" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN901"><span class="footnote">[11]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Интерпретатор, встретив фигурные скобки, раскрывает их и
          возвращает полученный список команд, которые затем и
          исполняет.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN947" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN947"><span class="footnote">[12]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Исключение: блок кода, являющийся частью конвейера, <span class="emphasis"><em class="EMPHASIS">может</em></span> быть запущен в дочернем
          процессе (<a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SUBSHELLSREF">subshell-е</a>).</p>
<pre class="PROGRAMLISTING">ls | { read firstline; read secondline; }
# Ошибка! Вложенный блок будет запущен в дочернем процессе,
# таким образом, вывод команды "ls" не может быть записан в переменные
# находящиеся внутри блока.
echo "Первая строка: $firstline; вторая строка: $secondline"  # Не работает!

# Спасибо S.C.
</pre>
          <br>
          <br>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN1772" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN1772"><span class="footnote">[13]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Аргумент <code class="REPLACEABLE"><em>$0</em></code> устанавливается
          вызывающим процессом. В соответствии с соглашениями, этот
          параметр содержит имя файла скрипта. См. страницы руководства
          для <strong class="COMMAND">execv</strong> (man execv).</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN1882" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN1882"><span class="footnote">[14]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Символ <span class="QUOTE">"!"</span>, помещенный в двойные
          кавычки, порождает сообщение об ошибке, если команда вводится
          <span class="emphasis"><em class="EMPHASIS">с командной строки</em></span>. Вероятно
          это связано с тем, что этот символ интерпретируется как
          попытка обращения к <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#HISTCOMMANDS">истории команд</a>. Однако внутри
          сценариев такой прием проблем не вызывает.</p>

          <p>Не менее любопытно поведение символа <span class="QUOTE">"\"</span>, употребляемого внутри
          двойных кавычек.</p>
<pre class="SCREEN"><code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo hello\!</strong></code>
<code class="COMPUTEROUTPUT">hello!</code>



<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo "hello\!"</strong></code>
<code class="COMPUTEROUTPUT">hello\!</code>



<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo -e x\ty</strong></code>
<code class="COMPUTEROUTPUT">xty</code>


<code class="PROMPT">bash$</code> <code class="USERINPUT"><strong>echo -e "x\ty"</strong></code>
<code class="COMPUTEROUTPUT">x       y</code>
             
</pre>
          (Спасибо Wayne Pollock за пояснения.) <br>
          <br>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN1906" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN1906"><span class="footnote">[15]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p><span class="QUOTE">"Разбиение на слова"</span>, в
          данном случае это означает разделение строки символов на
          некоторое число аргументов.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN2488" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN2488"><span class="footnote">[16]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>С флагом <span class="emphasis"><em class="EMPHASIS">suid</em></span>, на двоичных исполняемых
          файлах, надо быть очень осторожным, поскольку это может быть
          небезопасным. Установка флага <span class="emphasis"><em class="EMPHASIS">suid</em></span> на файлы-сценарии не имеет
          никакого эффекта.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN2508" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN2508"><span class="footnote">[17]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>В современных UNIX-системах, "sticky bit" больше
          не используется для файлов, только для каталогов.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN2722" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN2722"><span class="footnote">[18]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Как указывает S.C., даже заключение строки в кавычки, при
          построении сложных условий проверки, может оказаться
          недостаточным. <code class="USERINPUT"><strong>[ -n "$string" -o
          "$a" = "$b" ]</strong></code> в некоторых
          версиях Bash такая проверка может вызвать сообщение об
          ошибке, если строка <code class="VARNAME">$string</code> пустая. Безопаснее, в смысле
          отказоустойчивости, было бы добавить какой-либо символ к,
          возможно пустой, строке: <code class="USERINPUT"><strong>[ "x$string" != x -o
          "x$a" = "x$b" ]</strong></code> (символ
          <span class="QUOTE">"x"</span> не учитывается).</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN3728" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN3728"><span class="footnote">[19]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>PID текущего процесса хранится в переменной <code class="VARNAME">$$</code>.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN4011" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN4011"><span class="footnote">[20]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Слова <span class="QUOTE">"аргумент"</span> и <span class="QUOTE">"параметр"</span> очень часто
          используются как синонимы. В тексте данного документа, они
          применяются для обозначения одного и того же понятия, будь то
          аргумент, передаваемый скрипту из командной строки или
          входной параметр функции.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN4257" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN4257"><span class="footnote">[21]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Применяется к аргументам командной строки или входным
          параметрам <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FUNCTIONREF">функций</a>.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN4520" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN4520"><span class="footnote">[22]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Если $parameter "пустой",в неинтерактивных
          сценариях, то это будет приводить к завершению с <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXITCODESREF">кодом возврата <span class="RETURNVALUE">127</span></a> (<span class="QUOTE">"command not found"</span>).</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN5175" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN5175"><span class="footnote">[23]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Эти команды являются <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BUILTINREF">встроенными командами</a> языка сценариев
          командной оболочки (shell), в то время как <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#WHILELOOPREF">while</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#CASEESAC1">case</a> и т.п. -- являются <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#KEYWORDREF">зарезервированными словами</a>.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN5395" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN5395"><span class="footnote">[24]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Исключение из правил -- команда <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#TIMREF">time</a>, которая в официальной документации
          к Bash называется ключевым словом.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN5877" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN5877"><span class="footnote">[25]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Опция -- это аргумент, который управляет поведением
          сценария и может быть либо включен, либо выключен. Аргумент,
          который объединяет в себе несколько опций (ключей),
          определяет поведение сценария в соответствии с отдельными
          опциями, объединенными в данном аргументе..</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN6343" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN6343"><span class="footnote">[26]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Как правило, исходные тексты подобных библиотек, на языке
          C, располагаются в каталоге <code class="FILENAME">/usr/share/doc/bash-?.??/functions</code>.</p>

          <p>Обратите внимание: ключ <code class="OPTION">-f</code> команды <strong class="COMMAND">enable</strong> может отсутствовать в
          некоторых системах.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN6361" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN6361"><span class="footnote">[27]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Тот же эффект можно получить с помощью <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#DECLAREREF">typeset -fu</a>.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN6567" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN6567"><span class="footnote">[28]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Скрытыми считаются файлы, имена которых начинаются с
          точки, например, <code class="FILENAME">~/.Xdefaults</code>. Такие файлы не выводятся
          простой командой <strong class="COMMAND">ls</strong>, и не могут быть удалены
          командой <strong class="COMMAND">rm -rf *</strong>. Как правило, скрытыми
          делаются конфигурационные файлы в домашнем каталоге
          пользователя.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN7520" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN7520"><span class="footnote">[29]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Это верно только для GNU-версии команды <strong class="COMMAND">tr</strong>, поведение этой команды, в
          коммерческих UNIX-системах, может несколько отличаться.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN7816" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN7816"><span class="footnote">[30]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Команда <strong class="COMMAND">tar czvf archive_name.tar.gz *</strong>
          <span class="emphasis"><em class="EMPHASIS">включит</em></span> в архив все скрытые
          файлы (имена которых начинаются с точки) из <span class="emphasis"><em class="EMPHASIS">вложенных подкаталогов</em></span>. Это
          недокументированная <span class="QUOTE">"особенность"</span> GNU-версии
          <strong class="COMMAND">tar</strong>.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN8616" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN8616"><span class="footnote">[31]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Она реализует алгоритм симметричного блочного шифрования,
          в противоположность алгоритмам шифрования с <span class="QUOTE">"открытым ключом"</span>, из которых
          широко известен <strong class="COMMAND">pgp</strong>.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN8859" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN8859"><span class="footnote">[32]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p><a name="DAEMONREF"></a></p>

          <p><span class="emphasis"><em class="EMPHASIS">Демон</em></span> -- это некий фоновый
          процесс, не привязанный ни к одной из терминальных сессий.
          Демоны предназначены для выполнения определенного круга задач
          либо через заданные промежутки времени, либо по наступлению
          какого либо события.</p>

          <p>Слово <span class="QUOTE">"демон"</span> (<span class="QUOTE">"daemon"</span>), в греческой
          мифологии, употреблялось для обозначения призраков, духов,
          чего-то мистического, сверхестественного. В мире UNIX -- под
          словом демон подразумевается процесс, который
          "тихо" и "незаметно" выполняет свою
          работу.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN9380" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN9380"><span class="footnote">[33]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Фактически -- это сценарий, заимствованный из дистрибутива
          Debian Linux.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN9455" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN9455"><span class="footnote">[34]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p><span class="emphasis"><em class="EMPHASIS">Очередь печати</em></span> -- это группа
          заданий <span class="QUOTE">"ожидающих вывода"</span> на
          принтер.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN9514" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN9514"><span class="footnote">[35]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Эта тема прекрасно освещена в статье, которую написал Andy
          Vaught, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html" "http:="" www2.linuxjournal.com="" lj-issues="" issue41="" 2156.html"="" target="_top">Introduction to Named Pipes</a>, в сентябре
          1997 для <!--noindex--><a href="http://www.linuxjournal.com/" target="_top">Linux Journal</a><!--/noindex-->.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN9546" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN9546"><span class="footnote">[36]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>EBCDIC (произносится как <span class="QUOTE">"ebb-sid-ic"</span>) -- это
          аббревиатура от Extended Binary Coded Decimal Interchange
          Code (Расширенный Двоично-Десятичный Код Обмена Информацией).
          Это формат представления данных от IBM, не нашедший широкого
          применения. Не совсем обычное применение опции <code class="OPTION">conv=ebcdic</code> -- это использовать <strong class="COMMAND">dd</strong> для быстрого и легкого, но
          слабого, шифрования текстовых файлов.</p>
<pre class="PROGRAMLISTING">cat $file | dd conv=swab,ebcdic &gt; $file_encrypted
# Зашифрованный файл будет выглядеть как "абракадабра".
# опция swab добавлена для внесения большей неразберихи.

cat $file_encrypted | dd conv=swab,ascii &gt; $file_plaintext
# Декодирование.
</pre>
          <br>
          <br>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN9671" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN9671"><span class="footnote">[37]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p><span class="emphasis"><em class="EMPHASIS">макроопределение</em></span> -- это
          идентификатор, символическая константа, которая представляет
          некоторую последовательность команд, операций и
          параметров.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN9791" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN9791"><span class="footnote">[38]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Команда <strong class="COMMAND">userdel</strong> завершится неудачей, если
          удаляемый пользователь в этот момент работает с системой</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN10873" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN10873"><span class="footnote">[39]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Дополнительную информацию по записи компакт-дисков, вы
          найдете в статье Алекса Уизера (Alex Wither): <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html" "http:="" www2.linuxjournal.com="" lj-issues="" issue66="" 3335.html"="" target="_top">Creating CDs</a>, в октябрьском выпуске
          журнала <!--noindex--><a href="http://www.linuxjournal.com/" target="_top">Linux Journal</a><!--/noindex--> за 1999 год.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN11062" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN11062"><span class="footnote">[40]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Утилита <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MKE2FSREF">mke2fs</a>, с ключом <code class="OPTION">-c</code>, так же производит поиск поврежденных
          блоков.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN11188" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN11188"><span class="footnote">[41]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Пользователи небольших, десктопных Linux-систем
          предпочитают утилиты попроще, например <strong class="COMMAND">tar</strong>.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN11247" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN11247"><span class="footnote">[42]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>NAND -- логическая операция <span class="QUOTE">"И-НЕ"</span>. В общих чертах она
          напоминает вычитание.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN11451" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN11451"><span class="footnote">[43]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p><span class="emphasis"><em class="EMPHASIS">Замещающая команда</em></span> может быть
          внешней системной командой, внутренней (встроенной) командой
          или даже функцией в сценарии.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN11633" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN11633"><span class="footnote">[44]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p><span class="emphasis"><em class="EMPHASIS">дескриптор файла</em></span> -- это просто
          число, по которому система идентифицирует открытые файлы.
          Рассматривайте его как упрощенную версию указателя на
          файл.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN11642" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN11642"><span class="footnote">[45]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>При использрвании <code class="REPLACEABLE"><em>дескриптора с номером 5</em></code>
          могут возникать проблемы. Когда Bash порождает дочерний
          процесс, например командой <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXECREF">exec</a>, то дочерний процесс наследует
          дескриптор 5 как "открытый" (см. архив почты Чета
          Рамея (Chet Ramey), <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html" "http:="" www.geocrawler.com="" archives="" 3="" 342="" 1996="" 1="" 0="" 1939805="" "="" target="_top">SUBJECT: RE: File descriptor 5 is held
          open</a>) Поэтому, лучше не использовать этот дескриптор.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN11909" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN11909"><span class="footnote">[46]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>В качестве простейшего регулярного выражения можно
          привести строку, не содержащую никаких метасимволов.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN11937" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN11937"><span class="footnote">[47]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Поскольку с помощью <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#SEDREF">sed</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AWKREF">awk</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#GREPREF">grep</a> обрабатывают одиночные строки, то
          обычно символ перевода строки не принимается во внимание. В
          тех же случаях, когда производится разбор многострочного
          текста, метасимвол "точка" будет соответствовать
          символу перевода строки.</p>
<pre class="PROGRAMLISTING">#!/bin/bash

sed -e 'N;s/.*/[&amp;]/' &lt;&lt; EOF   # Встроенный документ
line1
line2
EOF
# OUTPUT:
# [line1
# line2]



echo

awk '{ $0=$1 "\n" $2; if (/line.1/) {print}}' &lt;&lt; EOF
line 1
line 2
EOF
# OUTPUT:
# line
# 1


# Спасибо S.C.

exit 0
</pre>
          <br>
          <br>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN12295" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN12295"><span class="footnote">[48]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Подстановка таких имен файлов <span class="emphasis"><em class="EMPHASIS">возможна</em></span>, но только при
          условии, что символ точки будет явно присутствовать в
          шаблоне.</p>
<pre class="PROGRAMLISTING">~/[.]bashrc    # Не будет соответствовать имени ~/.bashrc
~/?bashrc      # То же самое.
               # Метасимволы не могут соответствовать символу точки при подстановке имен файлов.

~/.[b]ashrc    # Имя ~./bashrc будет соответствовать данному шаблону
~/.ba?hrc      # Аналогично.
~/.bashr*      # Аналогично.

# Установка ключа "dotglob" отключает такое поведение интерпретатора.
# Спасибо S.C.
</pre>
          <br>
          <br>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN12454" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN12454"><span class="footnote">[49]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Имеет тот же эффект, что и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#NAMEDPIPEREF">именованные каналы</a> (временный
          файл), фактически, именованные каналы некогда использовались
          в операциях подстановки процессов.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN12558" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN12558"><span class="footnote">[50]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Механизм <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#IVRREF">косвенных ссылок</a> на переменные (см. <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EX78">Пример 34-2</a>) слишком неудобен для передачи
          аргументов по ссылке.</p>
<pre class="PROGRAMLISTING">#!/bin/bash

ITERATIONS=3  # Количество вводимых значений.
icount=1

my_read () {
  # При вызове my_read varname,
  # выводит предыдущее значение в квадратных скобках,
  # затем просит ввести новое значение.

  local local_var

  echo -n "Введите говое значение переменной "
  eval 'echo -n "[$'$1'] "'  # Прежнее значение.
  read local_var
  [ -n "$local_var" ] &amp;&amp; eval $1=\$local_var

  # Последовательность "And-list": если "local_var" не пуста, то ее значение переписывается в "$1".
}

echo

while [ "$icount" -le "$ITERATIONS" ]
do
  my_read var
  echo "Значение #$icount = $var"
  let "icount += 1"
  echo
done


# Спасибо Stephane Chazelas за этот поучительный пример.

exit 0
</pre>
          <br>
          <br>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN12587" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN12587"><span class="footnote">[51]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Команда <strong class="COMMAND">return</strong> -- это <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BUILTINREF">встроенная</a> команда Bash.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN12669" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN12669"><span class="footnote">[52]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p><a name="RECURSIONREF"></a> <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#MAYERREF">Herbert Mayer</a> определяет <span class="emphasis"><em class="EMPHASIS">рекурсию</em></span>, как <span class="QUOTE">"...описание алгоритма с помощью более
          простой версии того же самого алгоритма..."</span>
          Рекурсивной называется функция, которая вызывает самого
          себя.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN12675" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN12675"><span class="footnote">[53]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Слишком глубокая рекурсия может вызвать крах сценария.</p>
<pre class="PROGRAMLISTING">#!/bin/bash

recursive_function ()
{
(( $1 &lt; $2 )) &amp;&amp; recursive_function $(( $1 + 1 )) $2;
#  Увеличивать 1-й параметр до тех пор,
#+ пока он не станет равным, или не превысит, второму параметру.
}

recursive_function 1 50000  # Глубина рекурсии = 50,000!
# Само собой -- Segmentation fault.

#  Рекурсия такой глубины может "обрушить" даже программу, написанную на C,
#+ по исчерпании памяти, выделенной под сегмент стека.

# Спасибо S.C.

exit 0  # Этот сценарий завершает работу не здесь, а в результате ошибки Segmentation fault.
</pre>
          <br>
          <br>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN12698" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN12698"><span class="footnote">[54]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Однако, псевдонимы могут "раскручивать"
          позиционные параметры.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN12906" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN12906"><span class="footnote">[55]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Это не относится к таким оболочкам, как <strong class="COMMAND">csh</strong>, <strong class="COMMAND">tcsh</strong> и другим, которые не являются
          производными от классической Bourne shell (<strong class="COMMAND">sh</strong>).</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN12955" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN12955"><span class="footnote">[56]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Каталог <code class="FILENAME">/dev</code> содержит специальные файлы --
          точки монтирования физических и виртуальных устройств. Они
          занимают незначительное пространство на диске.</p>

          <p>Некоторые из устройств, такие как <code class="FILENAME">/dev/null</code>, <code class="FILENAME">/dev/zero</code> или <code class="FILENAME">/dev/urandom</code> -- являются виртуальными.
          Они не являются файлами физических устройств, система
          эмулирует эти устройства программным способом.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN12973" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN12973"><span class="footnote">[57]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p><span class="emphasis"><em class="EMPHASIS">Блочное устройство</em></span> читает и/или
          пишет данные целыми блоками, в отличие от <span class="emphasis"><em class="EMPHASIS">символьных устройств</em></span>, которые
          читают и/или пишут данные по одному символу. Примером
          блочного устройства может служить жесткий диск, CD-ROM.
          Примером символьного устройства -- клавиатура.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN13009" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN13009"><span class="footnote">[58]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Отдельные системные команды, такие как <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#PROCINFOREF">procinfo</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#FREEREF">free</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#VMSTATREF">vmstat</a>, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#LSDEVREF">lsdev</a> и <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#UPTIMEREF">uptime</a> делают это именно таким
          образом.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN13102" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN13102"><span class="footnote">[59]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p><!--noindex--><a href="http://bashdb.sourceforge.net/" target="_top">Bash debugger</a><!--/noindex--> (автор: Rocky Bernstein)
          частично возмещает этот недостаток.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN13188" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN13188"><span class="footnote">[60]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>В соответствии с соглашениями, сигнал с номером <code class="REPLACEABLE"><em>0</em></code> соответствует команде <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#EXITCOMMANDREF">exit</a>.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN13453" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN13453"><span class="footnote">[61]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Установка этого бита на файлы сценариев не имеет никакого
          эффекта.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN13625" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN13625"><span class="footnote">[62]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>ANSI -- аббревиатура от American National Standards
          Institute.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN13892" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN13892"><span class="footnote">[63]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>См. статью Marius van Oers, <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html" "http:="" www.virusbtn.com="" magazine="" archives="" 200204="" malshell.xml"="" target="_top">Unix Shell Scripting Malware</a>, а также
          ссылку на <span class="emphasis"><em class="EMPHASIS">Denning</em></span> в разделе <a href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#BIBLIOREF">Литература</a>.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN13946" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN13946"><span class="footnote">[64]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Chet Ramey обещал ввести в Bash ассоциативные массивы (они
          хорошо знакомы программистам, работающим с языком Perl) в
          одном из следующих релизов Bash.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN13971" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN13971"><span class="footnote">[65]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Кто может -- тот делает. Кто не может... тот получает
          сертификат MCSE.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN14612" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN14612"><span class="footnote">[66]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Если адресное пространство не указано, то, по-умолчанию, к
          обработке принимаются <span class="emphasis"><em class="EMPHASIS">все</em></span> строки.</p>
        </td>
      </tr>

      <tr>
        <td align="left" valign="top" width="5%"><a name="FTN.AEN14950" href="http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html#AEN14950"><span class="footnote">[67]</span></a></td>

        <td align="left" valign="top" width="95%">
          <p>Указание кода завершения за пределами установленного
          диапазона, приводит к возврату ошибочных кодов. Например,
          <strong class="COMMAND">exit 3809</strong> вернет код завершения,
          равный <span class="ERRORCODE">225</span>.</p>
        </td>
      </tr>
    </tbody></table>
  
<p></p>

					<div class="sbe"><div class="sbi">
						<script src="./Advanced Bash-Scripting Guide_files/es5-shims.min.js.Без названия"></script>
						<script src="./Advanced Bash-Scripting Guide_files/share.js.Без названия"></script>
						<div class="ya-share2 ya-share2_inited" data-services="collections,vkontakte,facebook,odnoklassniki,moimir,gplus,twitter"><div class="ya-share2__container ya-share2__container_size_m ya-share2__container_color-scheme_normal ya-share2__container_shape_normal"><ul class="ya-share2__list ya-share2__list_direction_horizontal"><li class="ya-share2__item ya-share2__item_service_collections"><a class="ya-share2__link" href="https://yandex.ru/collections/share/?url=http%3A%2F%2Frus-linux.net%2FMyLDP%2FBOOKS%2Fabs-guide%2Fflat%2Fabs-book.html&amp;description=Advanced%20Bash-Scripting%20Guide&amp;utm_source=share2" rel="nofollow noopener" target="_blank" title="Избранное"><span class="ya-share2__badge"><span class="ya-share2__icon"></span></span><span class="ya-share2__title">Избранное</span></a></li><li class="ya-share2__item ya-share2__item_service_vkontakte"><a class="ya-share2__link" href="https://vk.com/share.php?url=http%3A%2F%2Frus-linux.net%2FMyLDP%2FBOOKS%2Fabs-guide%2Fflat%2Fabs-book.html&amp;title=Advanced%20Bash-Scripting%20Guide&amp;utm_source=share2" rel="nofollow noopener" target="_blank" title="ВКонтакте"><span class="ya-share2__badge"><span class="ya-share2__icon"></span></span><span class="ya-share2__title">ВКонтакте</span></a></li><li class="ya-share2__item ya-share2__item_service_facebook"><a class="ya-share2__link" href="https://www.facebook.com/sharer.php?src=sp&amp;u=http%3A%2F%2Frus-linux.net%2FMyLDP%2FBOOKS%2Fabs-guide%2Fflat%2Fabs-book.html&amp;title=Advanced%20Bash-Scripting%20Guide&amp;utm_source=share2" rel="nofollow noopener" target="_blank" title="Facebook"><span class="ya-share2__badge"><span class="ya-share2__icon"></span></span><span class="ya-share2__title">Facebook</span></a></li><li class="ya-share2__item ya-share2__item_service_odnoklassniki"><a class="ya-share2__link" href="https://connect.ok.ru/offer?url=http%3A%2F%2Frus-linux.net%2FMyLDP%2FBOOKS%2Fabs-guide%2Fflat%2Fabs-book.html&amp;title=Advanced%20Bash-Scripting%20Guide&amp;utm_source=share2" rel="nofollow noopener" target="_blank" title="Одноклассники"><span class="ya-share2__badge"><span class="ya-share2__icon"></span></span><span class="ya-share2__title">Одноклассники</span></a></li><li class="ya-share2__item ya-share2__item_service_moimir"><a class="ya-share2__link" href="https://connect.mail.ru/share?url=http%3A%2F%2Frus-linux.net%2FMyLDP%2FBOOKS%2Fabs-guide%2Fflat%2Fabs-book.html&amp;title=Advanced%20Bash-Scripting%20Guide&amp;utm_source=share2" rel="nofollow noopener" target="_blank" title="Мой Мир"><span class="ya-share2__badge"><span class="ya-share2__icon"></span></span><span class="ya-share2__title">Мой Мир</span></a></li><li class="ya-share2__item ya-share2__item_service_twitter"><a class="ya-share2__link" href="https://twitter.com/intent/tweet?text=Advanced%20Bash-Scripting%20Guide&amp;url=http%3A%2F%2Frus-linux.net%2FMyLDP%2FBOOKS%2Fabs-guide%2Fflat%2Fabs-book.html&amp;utm_source=share2" rel="nofollow noopener" target="_blank" title="Twitter"><span class="ya-share2__badge"><span class="ya-share2__icon"></span></span><span class="ya-share2__title">Twitter</span></a></li></ul></div></div>
					</div><div class="sbi"><h4>Если вам понравилась статья, поделитесь ею с друзьями:</h4></div></div>
					<!-- Контекст от Гугла -->
<!-- блок Гугла -->

<script async="" src="./Advanced Bash-Scripting Guide_files/f(1).txt"></script>
<!-- rus-linux-banner-728x90 -->
<ins class="adsbygoogle" style="display:inline-block;width:728px;height:90px" data-ad-client="ca-pub-0144063130920108" data-ad-slot="5262754882"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>


					<hr><div class="eval"> </div>			</div>
		</div>
					</div>
			</div>
		</div>
	</div>
	
		<footer>
	<ul class="menu_box">
	<li class="lbtn"><a href="http://rus-linux.net/" title="Титульная страница сайта">Новости</a></li>
	<li><a href="http://rus-linux.net/lib.php?name=/MyLDP/index.html" title="Тематический каталог книг и статей, опубликованных на сайте">Библиотека</a></li>
	<li><a href="http://rus-linux.net/lib.php?name=/MyLDP/BOOKS/books.html" title="Е-книги по Линукс для чтения он-лайн">Е-книги</a></li>
	<li><a href="http://rus-linux.net/kos.php?name=/inc/site.html#avtory" title="Авторы и переводчики, их статьи, книги и переводы">Авторское</a></li>
	<li><!--noindex--><a href="http://linux-ru.ru/" rel="nofollow" title="Форум по ОС Linux и свободному ПО">Форум</a><!--/noindex--></li>
	<li><a href="http://rus-linux.net/lib.php?name=/txt/kat-full.html" title="Каталог ссылок на публикации в Сети по ОС GNU/Linux">Каталог ссылок</a></li>
	<li><a href="http://rus-linux.net/lib.php?name=/po/linapp.koi" title="Каталог программного обеспечения для ОС GNU/Linux">Каталог ПО</a></li>
	<li><a href="http://rus-linux.net/kos.php?name=/inc/site.html" title="О сайте">О сайте</a></li>
	<li><a href="http://rus-linux.net/lib.php?name=/sitemap.html" title="Карта сайта">Карта сайта</a></li>
</ul>
<div id="footer_gnr">
</div><noindex>
<div id="counters">
		<div class="tab_cell adl">
			<div class="ib">
	<!-- RotaBan.ru Zone Code -->
	<div id="rotaban_200118" class="rbrocks rotaban_d93b9b532bea4b0f8d7c5f30dafb2ba3"></div>
	<!-- END RotaBan.ru Zone Code -->
			</div>
		</div>

		<div class="tab_cell adc">
			<div class="ib">
				(C) В.А.Костромин, 1999 - 2020 г.
			</div>
		</div>

		<div class="tab_cell adr">
			<div class="ib">
				<!--noindex--><a href="http://www.yandex.ru/cy?base=0&amp;host=rus-linux.net"><img src="./Advanced Bash-Scripting Guide_files/cycounter" name="Графический объект1" alt="Яндекс цитирования" align="BOTTOM" width="88" height="31" border="0"></a><!--/noindex-->
				<!--Rating@Mail.ru logo-->
				<a target="_top" href="http://top.mail.ru/jump?from=55285">
					<img src="./Advanced Bash-Scripting Guide_files/counter(1)" border="0" height="31" width="88" alt="Рейтинг@Mail.ru">
				</a>

				<!--LiveInternet logo--><a href="http://www.liveinternet.ru/click" target="_blank"><img src="./Advanced Bash-Scripting Guide_files/logo" title="LiveInternet: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня" alt="" border="0" width="88" height="31"></a><!--/LiveInternet-->

			</div>
		</div>
</div>
</noindex>
<p>&nbsp;</p>	</footer>
	<div id="page_bottom">

<!-- Uptolike -->
<script async="" type="text/javascript" src="./Advanced Bash-Scripting Guide_files/zp.js.Без названия"></script>
<!-- Uptolike -->

</div>
	
	<script type="text/javascript">
		TimeLoad2=(new Date()).getTime() - TimeLoad1; TimeMax+=TimeAdd;
		//document.write("<p class='center'>TimeLoad="+ TimeLoad2+ "  TimeMax="+ TimeMax+ "</p>");
		if (TimeLoad2 < TimeMax) {
			<!-- RotaBan.ru Ad Code -->
			(function(){
				var rb = document.createElement('script');
				d = new Date();
				d.setHours(0);
				d.setMinutes(0);
				d.setSeconds(0);
				d.setMilliseconds(0);
				rb.type = 'text/javascript';
				rb.async = true;
				rb.src = '//s1.rotaban.ru/rotaban.js?v=' + d.getTime();
				(document.getElementsByTagName('head')[0]||document.getElementsByTagName('body')[0]).appendChild(rb);
			})();
			<!-- END RotaBan.ru Ad Code -->		
		};
	</script>

	<script type="text/javascript">
						TimeLoad2=(new Date()).getTime() - TimeLoad1; TimeMax+=TimeAdd;
			//document.write("<p class='center'>TimeLoad="+ TimeLoad2+ "  TimeMax="+ TimeMax + "</p>");
			if (TimeLoad2 < TimeMax) {
				sign_bad=1;
				(function(w, d, n, s, t) {
					w[n] = w[n] || [];
					w[n].push(function() {
						Ya.Direct.insertInto(49531, "yandex_ad", {
							stat_id: 6,
							ad_format: "direct",
							font_size: 0.8,
							type: "vertical",
							border_type: "collapse",
							limit: 4,
							title_font_size: 4,
							links_underline: true,
							site_bg_color: "FFFFFF",
							header_bg_color: "FEEAC7",
							border_color: "FBE5C0",
							title_color: "0000CC",
							url_color: "006600",
							text_color: "000000",
							hover_color: "0066FF",
							sitelinks_color: "0000CC",
							favicon: true,
							no_sitelinks: false
						});
					});
					t = d.getElementsByTagName("script")[0];
					s = d.createElement("script");
					s.src = "//an.yandex.ru/system/context.js";
					s.type = "text/javascript";
					s.async = true;
					t.parentNode.insertBefore(s, t);
				})(window, document, "yandex_context_callbacks");

							};

/*		if (sign_bad) { window.onload=function(){msgbad();};};
		function msgbad() {
			var e=document.getElementById("yandex_ad");
			if (!e) { e=0; } else { e=e.innerHTML.length; };
			if (e < 100) {
				e=document.getElementById("obr");
				e.innerHTML="<div id='mab'></div>";
			};
		}; 
*/
	</script>



<!-- 2019-11-30 Добавлен код Mixmarket -->
<script>
document.write('<scr' + 'ipt language="javascript" type="text/javascript" src="http://4294911548.kt.mixmarket.biz/show/4294911548/?div=mixkt_4294911548&r=' + escape(document.referrer) + '&rnd=' + Math.round(Math.random() * 100000) + '" charset="windows-1251"><' + '/scr' + 'ipt>');
</script><script language="javascript" type="text/javascript" src="http://4294911548.kt.mixmarket.biz/show/4294911548/?div=mixkt_4294911548&amp;r=http%3A//rus-linux.net/lib.php%3Fname%3D/MyLDP/BOOKS/Bash-Guide-1.12-ru/bash-guide-00.html&amp;rnd=30630" charset="windows-1251"></script>
<!-- 2019-11-30 Добавлен код Mixmarket -->




<iframe name="ym-native-frame" title="ym-native-frame" frameborder="0" aria-hidden="true" style="opacity: 0 !important; width: 0px !important; height: 0px !important; position: absolute !important; left: 100% !important; bottom: 100% !important; border: 0px !important;" src="./Advanced Bash-Scripting Guide_files/saved_resource.html"></iframe><iframe src="./Advanced Bash-Scripting Guide_files/impression.html" style="width: 1px; height: 1px; position: absolute; left: -100px; top: 0px; border: none;"></iframe><script type="text/javascript" charset="UTF-8" async="" src="./Advanced Bash-Scripting Guide_files/saved_resource"></script><iframe src="./Advanced Bash-Scripting Guide_files/support.html" style="width: 1px; height: 1px; left: -100px; top: -100px; position: absolute; margin: 0px; border: 0px;"></iframe></body><style id="stylus-11" type="text/css" class="stylus">* {
    font-family: "Pragmata Pro Mono Regular";
}
</style></html>